@agoric/swingset-liveslots 0.10.3-other-dev-3eb1a1d.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 (86) hide show
  1. package/package.json +26 -26
  2. package/src/boyd-gc.d.ts +12 -0
  3. package/src/boyd-gc.d.ts.map +1 -0
  4. package/src/cache.d.ts +71 -0
  5. package/src/cache.d.ts.map +1 -0
  6. package/src/capdata.d.ts +16 -0
  7. package/src/capdata.d.ts.map +1 -0
  8. package/src/capdata.js +16 -8
  9. package/src/collectionManager.d.ts +47 -0
  10. package/src/collectionManager.d.ts.map +1 -0
  11. package/src/collectionManager.js +1 -0
  12. package/src/facetiousness.d.ts +25 -0
  13. package/src/facetiousness.d.ts.map +1 -0
  14. package/src/index.d.ts +4 -0
  15. package/src/index.d.ts.map +1 -0
  16. package/src/kdebug.d.ts +7 -0
  17. package/src/kdebug.d.ts.map +1 -0
  18. package/src/liveslots.d.ts +42 -0
  19. package/src/liveslots.d.ts.map +1 -0
  20. package/src/liveslots.js +6 -4
  21. package/src/message.d.ts +49 -0
  22. package/src/message.d.ts.map +1 -0
  23. package/src/message.js +7 -3
  24. package/src/parseVatSlots.d.ts +125 -0
  25. package/src/parseVatSlots.d.ts.map +1 -0
  26. package/src/types.d.ts +81 -0
  27. package/src/types.d.ts.map +1 -0
  28. package/src/types.js +6 -5
  29. package/src/vatDataTypes.d.ts +170 -0
  30. package/src/vatDataTypes.d.ts.map +1 -0
  31. package/src/vatDataTypes.ts +272 -0
  32. package/src/vatstore-iterators.d.ts +4 -0
  33. package/src/vatstore-iterators.d.ts.map +1 -0
  34. package/src/vatstore-usage.md +198 -0
  35. package/src/virtualObjectManager.d.ts +44 -0
  36. package/src/virtualObjectManager.d.ts.map +1 -0
  37. package/src/virtualObjectManager.js +70 -14
  38. package/src/virtualReferences.d.ts +61 -0
  39. package/src/virtualReferences.d.ts.map +1 -0
  40. package/src/vpid-tracking.md +92 -0
  41. package/src/watchedPromises.d.ts +31 -0
  42. package/src/watchedPromises.d.ts.map +1 -0
  43. package/src/watchedPromises.js +19 -12
  44. package/test/collections.test.js +25 -4
  45. package/test/dummyMeterControl.d.ts +2 -0
  46. package/test/dummyMeterControl.d.ts.map +1 -0
  47. package/test/engine-gc.d.ts +3 -0
  48. package/test/engine-gc.d.ts.map +1 -0
  49. package/test/gc-and-finalize.d.ts +5 -0
  50. package/test/gc-and-finalize.d.ts.map +1 -0
  51. package/test/gc-helpers.js +2 -2
  52. package/test/handled-promises.test.js +529 -163
  53. package/test/initial-vrefs.test.js +12 -18
  54. package/test/liveslots-helpers.d.ts +64 -0
  55. package/test/liveslots-helpers.d.ts.map +1 -0
  56. package/test/liveslots-helpers.js +1 -0
  57. package/test/liveslots-real-gc.test.js +11 -9
  58. package/test/liveslots.test.js +3 -3
  59. package/test/storeGC/lifecycle.test.js +13 -12
  60. package/test/util.d.ts +25 -0
  61. package/test/util.d.ts.map +1 -0
  62. package/test/util.js +2 -2
  63. package/test/vat-util.d.ts +9 -0
  64. package/test/vat-util.d.ts.map +1 -0
  65. package/test/virtual-objects/state-shape.test.js +312 -221
  66. package/test/virtual-objects/virtualObjectGC.test.js +37 -36
  67. package/test/virtual-objects/virtualObjectManager.test.js +41 -63
  68. package/test/vo-test-harness.test.js +13 -9
  69. package/test/waitUntilQuiescent.d.ts +3 -0
  70. package/test/waitUntilQuiescent.d.ts.map +1 -0
  71. package/tools/fakeCollectionManager.d.ts +14 -0
  72. package/tools/fakeCollectionManager.d.ts.map +1 -0
  73. package/tools/fakeVirtualObjectManager.d.ts +32 -0
  74. package/tools/fakeVirtualObjectManager.d.ts.map +1 -0
  75. package/tools/fakeVirtualSupport.d.ts +278 -0
  76. package/tools/fakeVirtualSupport.d.ts.map +1 -0
  77. package/tools/prepare-strict-test-env.d.ts +37 -0
  78. package/tools/prepare-strict-test-env.d.ts.map +1 -0
  79. package/tools/prepare-test-env.d.ts +2 -0
  80. package/tools/prepare-test-env.d.ts.map +1 -0
  81. package/tools/setup-vat-data.d.ts +9 -0
  82. package/tools/setup-vat-data.d.ts.map +1 -0
  83. package/tools/setup-vat-data.js +0 -1
  84. package/tools/vo-test-harness.d.ts +33 -0
  85. package/tools/vo-test-harness.d.ts.map +1 -0
  86. package/tools/vo-test-harness.js +21 -0
@@ -0,0 +1,272 @@
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
+ // used to omit the 'context' parameter
34
+ type OmitFirstArg<F> = F extends (x: any, ...args: infer P) => infer R
35
+ ? (...args: P) => R
36
+ : never;
37
+
38
+ // The type of a passable local object with methods.
39
+ // An internal helper to avoid having to repeat `O`.
40
+ type PrimaryRemotable<O> = O & RemotableObject & RemotableBrand<object, O>;
41
+
42
+ export type KindFacet<O> = PrimaryRemotable<{
43
+ [K in keyof O]: OmitFirstArg<O[K]>; // omit the 'context' parameter
44
+ }>;
45
+
46
+ export type KindFacets<B> = {
47
+ [FacetKey in keyof B]: KindFacet<B[FacetKey]>;
48
+ };
49
+
50
+ export type KindContext<S, F> = { state: S; self: KindFacet<F> };
51
+ export type MultiKindContext<S, B> = { state: S; facets: KindFacets<B> };
52
+
53
+ export type PlusContext<C, M extends (...args: any[]) => any> = (
54
+ c: C,
55
+ ...args: Parameters<M>
56
+ ) => ReturnType<M>;
57
+
58
+ export type FunctionsPlusContext<
59
+ C,
60
+ O extends Record<string, (...args: any[]) => any>,
61
+ > = {
62
+ [K in keyof O]: PlusContext<C, O[K]>;
63
+ };
64
+
65
+ declare class DurableKindHandleClass {
66
+ private descriptionTag: string;
67
+ }
68
+ export type DurableKindHandle = DurableKindHandleClass;
69
+
70
+ /**
71
+ * Grab bag of options that can be provided to `defineDurableKind` and its
72
+ * siblings. Not all options are meaningful in all contexts. See the
73
+ * doc-comments on each option.
74
+ */
75
+ export type DefineKindOptions<C> = {
76
+ /**
77
+ * If provided, the `finish` function will be called after the instance is
78
+ * made and internally registered, but before it is returned. The finish
79
+ * function is to do any post-intantiation initialization that should be
80
+ * done before exposing the object to its clients.
81
+ */
82
+ finish?: (context: C) => void;
83
+
84
+ /**
85
+ * If provided, it describes the shape of all state records of instances
86
+ * of this kind.
87
+ */
88
+ stateShape?: StateShape;
89
+
90
+ /**
91
+ * If a `receiveAmplifier` function is provided to an exo class kit definition,
92
+ * it will be called with an `Amplify` function. If provided to the definition
93
+ * of a normal exo or exo class, the definition will throw, since only
94
+ * exo kits can be amplified.
95
+ * An `Amplify` function is a function that takes a facet instance of
96
+ * this class kit as an argument, in which case it will return the facets
97
+ * record, giving access to all the facet instances of the same cohort.
98
+ */
99
+ receiveAmplifier?: ReceivePower<Amplify>;
100
+
101
+ /**
102
+ * If a `receiveInstanceTester` function is provided, it will be called
103
+ * during the definition of the exo class or exo class kit with an
104
+ * `IsInstance` function. The first argument of `IsInstance`
105
+ * is the value to be tested. When it may be a facet instance of an
106
+ * exo class kit, the optional second argument, if provided, is
107
+ * a `facetName`. In that case, the function tests only if the first
108
+ * argument is an instance of that facet of the associated exo class kit.
109
+ */
110
+ receiveInstanceTester?: ReceivePower<IsInstance>;
111
+
112
+ // TODO properties above are identical to those in FarClassOptions.
113
+ // These are the only options that should be exposed by
114
+ // vat-data's public virtual/durable exo APIs. This DefineKindOptions
115
+ // should explicitly be a subtype, where the methods below are only for
116
+ // internal use, i.e., below the exo level.
117
+
118
+ /**
119
+ * As a kind option, intended for internal use only.
120
+ * Meaningful to `makeScalarBigMapStore` and its siblings. These maker
121
+ * fuctions will make either virtual or durable stores, depending on
122
+ * this flag. Defaults to off, making virtual but not durable collections.
123
+ *
124
+ * Generally, durable collections are provided with `provideDurableMapStore`
125
+ * and its sibling, which use this flag internally. If you do not make
126
+ * durable collections by other means, you can consider this as
127
+ * intended for internal use only.
128
+ */
129
+ durable?: boolean;
130
+
131
+ /**
132
+ * Intended for internal use only.
133
+ * Should the raw methods receive their `context` argument as their first
134
+ * argument or as their `this` binding? For `defineDurableKind` and its
135
+ * siblings (including `prepareSingleton`), this defaults to off, meaning that
136
+ * their behavior methods receive `context` as their first argument.
137
+ * `prepareExoClass` and its siblings (including `prepareExo`) use
138
+ * this flag internally to indicate that their methods receive `context`
139
+ * as their `this` binding.
140
+ */
141
+ thisfulMethods?: boolean;
142
+
143
+ /**
144
+ * Intended for internal use only.
145
+ * Only applicable if this is a class kind. A class kit kind should use
146
+ * `interfaceGuardKit` instead.
147
+ *
148
+ * If an `interfaceGuard` is provided, then the raw methods passed alongside
149
+ * it are wrapped by a function that first checks that this method's guard
150
+ * pattern is satisfied before calling the raw method.
151
+ *
152
+ * In `defineDurableKind` and its siblings, this defaults to `undefined`.
153
+ * Exo classes use this internally to protect their raw class methods
154
+ * using the provided interface.
155
+ * In absence, an exo is protected anyway, while a bare kind is
156
+ * not (detected by `!thisfulMethods`),
157
+ */
158
+ interfaceGuard?: InterfaceGuard;
159
+
160
+ /**
161
+ * Intended for internal use only.
162
+ * Only applicable if this is a class kit kind. A class kind should use
163
+ * `interfaceGuard` instead.
164
+ *
165
+ * If an `interfaceGuardKit` is provided, then each member of the
166
+ * interfaceGuardKit is used to guard the corresponding facet of the
167
+ * class kit.
168
+ *
169
+ * In `defineDurableKindMulti` and its siblings, this defaults to `undefined`.
170
+ * Exo class kits use this internally to protect their facets.
171
+ * In absence, an exo is protected anyway, while a bare kind is
172
+ * not (detected by `!thisfulMethods`),
173
+ */
174
+ interfaceGuardKit?: InterfaceGuardKit;
175
+ };
176
+
177
+ export type VatData = {
178
+ // virtual kinds
179
+ /** @deprecated Use defineVirtualExoClass instead */
180
+ defineKind: <P extends Array<any>, S, F>(
181
+ tag: string,
182
+ init: (...args: P) => S,
183
+ facet: F,
184
+ options?: DefineKindOptions<KindContext<S, F>>,
185
+ ) => (...args: P) => KindFacet<F>;
186
+
187
+ /** @deprecated Use defineVirtualExoClassKit instead */
188
+ defineKindMulti: <P extends Array<any>, S, B>(
189
+ tag: string,
190
+ init: (...args: P) => S,
191
+ behavior: B,
192
+ options?: DefineKindOptions<MultiKindContext<S, B>>,
193
+ ) => (...args: P) => KindFacets<B>;
194
+
195
+ // durable kinds
196
+ makeKindHandle: (descriptionTag: string) => DurableKindHandle;
197
+
198
+ /** @deprecated Use defineDurableExoClass instead */
199
+ defineDurableKind: <P extends Array<any>, S, F>(
200
+ kindHandle: DurableKindHandle,
201
+ init: (...args: P) => S,
202
+ facet: F,
203
+ options?: DefineKindOptions<KindContext<S, F>>,
204
+ ) => (...args: P) => KindFacet<F>;
205
+
206
+ /** @deprecated Use defineDurableExoClassKit instead */
207
+ defineDurableKindMulti: <P extends Array<any>, S, B>(
208
+ kindHandle: DurableKindHandle,
209
+ init: (...args: P) => S,
210
+ behavior: B,
211
+ options?: DefineKindOptions<MultiKindContext<S, B>>,
212
+ ) => (...args: P) => KindFacets<B>;
213
+
214
+ providePromiseWatcher: WatchedPromisesManager['providePromiseWatcher'];
215
+ watchPromise: WatchedPromisesManager['watchPromise'];
216
+
217
+ makeScalarBigMapStore: <K, V>(
218
+ label: string,
219
+ options?: StoreOptions,
220
+ ) => MapStore<K, V>;
221
+ makeScalarBigWeakMapStore: <K, V>(
222
+ label: string,
223
+ options?: StoreOptions,
224
+ ) => WeakMapStore<K, V>;
225
+
226
+ makeScalarBigSetStore: <K>(
227
+ label: string,
228
+ options?: StoreOptions,
229
+ ) => SetStore<K>;
230
+ makeScalarBigWeakSetStore: <K>(
231
+ label: string,
232
+ options?: StoreOptions,
233
+ ) => WeakSetStore<K>;
234
+ canBeDurable: (specimen: unknown) => boolean;
235
+ };
236
+
237
+ // The JSDoc is repeated here and at the function definition so it appears
238
+ // in IDEs where it's used, regardless of type resolution.
239
+ export interface PickFacet {
240
+ /**
241
+ * When making a multi-facet kind, it's common to pick one facet to
242
+ * expose. E.g.,
243
+ *
244
+ * const makeFoo = (a, b, c, d) => makeFooBase(a, b, c, d).self;
245
+ *
246
+ * This helper reduces the duplication:
247
+ *
248
+ * const makeFoo = pickFacet(makeFooBase, 'self');
249
+ */
250
+ <M extends (...args: any[]) => any, F extends keyof ReturnType<M>>(
251
+ maker: M,
252
+ facetName: F,
253
+ ): (...args: Parameters<M>) => ReturnType<M>[F];
254
+ }
255
+
256
+ /** @deprecated Use prepareExoClass instead */
257
+ export type PrepareKind = <P extends Array<any>, S, F>(
258
+ baggage: Baggage,
259
+ tag: string,
260
+ init: (...args: P) => S,
261
+ facet: F,
262
+ options?: DefineKindOptions<KindContext<S, F>>,
263
+ ) => (...args: P) => KindFacet<F>;
264
+
265
+ /** @deprecated Use prepareExoClassKit instead */
266
+ export type PrepareKindMulti = <P extends Array<any>, S, B>(
267
+ baggage: Baggage,
268
+ tag: string,
269
+ init: (...args: P) => S,
270
+ behavior: B,
271
+ options?: DefineKindOptions<MultiKindContext<S, B>>,
272
+ ) => (...args: P) => KindFacets<B>;
@@ -0,0 +1,4 @@
1
+ export function enumerateKeysStartEnd(syscall: any, start: any, end: any, checkF: any): Generator<any, void, unknown>;
2
+ export function enumerateKeysWithPrefix(syscall: any, prefix: any): Generator<any, void, unknown>;
3
+ export function prefixedKeysExist(syscall: any, prefix: any): boolean;
4
+ //# sourceMappingURL=vatstore-iterators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vatstore-iterators.d.ts","sourceRoot":"","sources":["vatstore-iterators.js"],"names":[],"mappings":"AAIA,sHAeC;AAMD,kGASC;AAGD,sEAGC"}
@@ -0,0 +1,198 @@
1
+ # How Liveslots Uses the Vatstore
2
+
3
+ Each vat gets exclusive access to a portion of the kernel's `kvStore`, implemented with a simple prefix: when vat `v6` uses `syscall.vatstoreSet('key', 'value')`, the kvStore records the value in key `v6.vs.key`.
4
+
5
+ Userspace gets an attenuated object named `vatPowers.vatstore`. When userspace calls `vatPowers.vatstore.set('key', 'value')`, liveslots performs `syscall.vatstoreSet('vvs.key', value)`, which results in a kernel kvStore entry under key `v6.vs.vvs.key`.
6
+
7
+ The rest of the vat's keyspace is used by liveslots:
8
+
9
+ * virtual object Kind metainformation
10
+ * data for each virtual object
11
+ * virtual collection metainformation and entries
12
+ * reference counts for virtual objects (tracking references from other virtual objects)
13
+ * export status for virtual objects
14
+ * the id of the "baggage" object, delivered across vat upgrades
15
+
16
+ This file describes the layout of the vatstore keyspace.
17
+
18
+ # vref virtual/durable annotations
19
+
20
+ When vats export object references into the kernel, they create "vrefs" as reference identifiers. For non-virtual objects (ephemeral "Remotables", held in RAM rather than the DB), these take the form of `o+NN` (e.g. `o+0`, `o+12`, `o+937`). Virtual and durable exported objects get an additional `v` or `d` annotation, so their vrefs start with e.g. `o+v99` or `o+v132` for virtual objects, and `o+d3` or `o+d77` for durable objects. The kernel can use these annotations to assist in the cleanup process when a vat is upgraded, and non-durable objects are abandoned.
21
+
22
+ Kind handles are necessarily durable, as is the "baggage" object. Promises are necessarily ephemeral, so vat-allocated promise vrefs (aka "vpids") always use the `p+NN` form, and never have a `v` or `d` annotation.
23
+
24
+ # Counters
25
+
26
+ Liveslots maintains three durable counters to create the distinct vrefs that it transmits to the kernel. These counters are initialized when `startVat` is called to create the first incarnation of a vat (see `initialIDCounters` and `initializeIDCounters` in [liveslots.js](./liveslots.js)), and written to the vatstore at the end of each delivery as a JSON-serialized record at key `idCounters` (see `flushIDCounters`).
27
+
28
+ * `exportID`: an integer indicating the ID of the next exported Remotable or defined Kind and incremented upon each allocation of such a value. Technically starts at 1, but that is mostly irrelevant because the root object itself is associated with 0 and many initial values are claimed before any userspace vat code has a chance to run (described below).
29
+ * `collectionID`: an integer indicating the ID of the next collection and incremented upon each allocation of a new collection. Starts at 1, which is claimed by "[baggage](#baggage)".
30
+ * `promiseID`: an integer indicating the ID for the next exported promise (including a promise implicitly created for outbound-message results) and incremented upon each allocation. Starts at 5.
31
+
32
+ The current version of liveslots consumes the first ten exportIDs (covering `o+0` through `o+9`) during vat startup, leaving `10` as the first exportID available for userspace.
33
+
34
+ * `o+0`: root object
35
+ * `o+d1`: identifies the KindHandle Kind ID, each `o+d1/${kindHandleID}` instance of which is a KindHandle
36
+ * `o+v2` through `o+v5`: KindHandles for the built-in [virtual collections](#virtualdurable-collections-aka-stores)
37
+ * `o+d6` through `o+d9`: KindHandles for the built-in [durable collections](#virtualdurable-collections-aka-stores)
38
+ * `o+10` / `o+v10` / `o+d10`: first available for userspace Remotables or Kinds
39
+
40
+
41
+ # Virtual Object Kinds
42
+
43
+ Vats can use `VatData.defineKind()` to define categories (classes) of virtual data (see [Virtual and Durable Objects](../../SwingSet/docs/virtual-objects.md)). The effective schema for each "Kind" contains an interface name, a set of `state` property names, and a list of facet names (which may be empty, indicating a single-facet Kind).
44
+
45
+ The standard Kind is "single-facet", meaning that each instance of the virtual object yields exactly one "Representative". However many security patterns require a collection of "Facet" Representatives which share access to common state. These Facets are all created at the same time and returned in a single record called a "cohort".
46
+
47
+ `defineKind` also specifies the runtime behavior: an `init` function called to create the initial state of each instance, a `behavior` record to provide methods for each instance, and an optional `finish` function to perform post-initialization tasks like registering the new object in a collection. `defineKind` returns a "kind constructor", typically named e.g. `makeFoo()` to make instances of the "foo" kind.
48
+
49
+ Each time the kind constructor is called, a new "baseref" is allocated for the cohort, and the (one or multiple) facet Representatives are created. Each Representative/Facet gets a separate vref, all of which are extensions of the baseref.
50
+ Those vrefs are used when interacting with the kernel (in `syscall.send` etc.), and in virtualized data (inside the capdata `slots` that point to other objects), but the vatstore keys that track GC refcounts and export status use the "baseref" instead.
51
+
52
+ The baseref is built out of two pieces separated by a literal `/`:
53
+
54
+ 1. Prefixed Kind ID, e.g. `o+v11` or `o+d11`. These are allocated using the same exportID [counter](#counters) as exported Remotables (JavaScript objects marked with `Far`), meaning exported objects and Kind IDs share a numberspace.
55
+ 2. Instance ID, an integer. `1` for the first instance of each Kind and incremented for each subsequent instance.
56
+
57
+ The vref for a Representative of a single-facet virtual Kind is just the `o+v${kindID}/${instanceID}` baseref. The vref for a Representative of a facet of a multi-facet virtual Kind extends that to `o+v${kindID}/${instanceID}:${facetID}`, where the additional component is:
58
+
59
+ 3. Facet ID, an integer. `0` for the first facet and incremented for each subsequent facet.
60
+
61
+ In a c-list or virtualized data, you may see vrefs like these:
62
+
63
+ * `o-3`: an imported Presence, pointing to some object in a different vat
64
+ * `o+0`: the root object, a plain Remotable
65
+ * `o+10`: another plain Remotable, exported from this vat or stored in virtualized data
66
+ * `o+d11/1`: a Representative for the first instance of single-facet virtual Kind `o+v11`
67
+ * `o+d11/2`: a Representative for the second instance of single-facet virtual Kind `o+v11`
68
+ * `o+d12/1:0`: the first facet of the first instance of a multi-facet durable Kind `o+d12`
69
+ * `o+d12/1:1`: the second facet of that same instance
70
+ * `o+d12/2:0`: the first facet of a different instance
71
+ * `o+d12/3:0`: the first facet of yet another different instance
72
+
73
+ Each instance of a virtual object stores state in a vatstore key indexed by the baseref. If `o+d12/1:0` and `o+d12/1:1` are the facet vrefs for a cohort whose baseref is `o+d12/1`, the cohort's shared state will be stored by the virtual object manager in `vom.o+d12/1` as a JSON-serialized record. The keys of this record are property names: if the Kind uses `state.prop1`, the record will have a key named `prop1`. For each property, the value is a `{ body: string, slots: any[] }` capdata record with string-valued slot items (and unlike the treatment of capdata in many other parts of the system, it is not serialized independently of the enclosing structure).
74
+
75
+ * `v6.vs.vom.o+d12/1` : `{"booleanProp":{"body":"true","slots":[]},"arrayProp":{"body":"[]","slots":[]}}`
76
+
77
+ In the refcounting portion of the vatstore (`vom.rc.${baseref}`), you will see baserefs:
78
+
79
+ * `v6.vs.vom.rc.o+10`: the count of virtualized references to plain Remotable `o+10` (held in RAM)
80
+ * `v6.vs.vom.rc.o+d12/1`: the count of references to any member of the cohort for the first instance of durable Kind `o+d12`
81
+ * This Kind might be single-facet or multi-facet.
82
+ * References to distinct facets of the same cohort are counted independently. For example, if one object references both the first and second facets (`o+d12/1:0` and `o+d12/1:1`), it accounts for two increments to this value.
83
+
84
+ In the export-status portion of the vatstore (`vom.es.${baseref}`), you will see baserefs, and any facets are tracked in the value, not the key:
85
+
86
+ * `v6.vs.vom.es.o+10` records the export status for plain Remotable `o+10`
87
+ * value `r`: the plain Remotable has been exported and is "reachable" by the kernel
88
+ * value `s`: the Remotable was exported, the kernel dropped it, and is still "recognizable" by the kernel ("s" for "see", refer to [Garbage Collection in SwingSet](../../SwingSet/docs/garbage-collection.md) for details)
89
+ * If the kernel can neither reach nor recognize the export, the vatstore key will be missing entirely.
90
+ * `v6.vs.vom.es.o+d12/1` records the export status for all facets of the durable object whose vref is `o+d12/1` (i.e., the first instance of durable Kind `o+d12`)
91
+ * If the Kind is single-facet, the value will be the same as for a plain Remotable: a single `r` or `s` character
92
+ * If the Kind is multi-facet, the value will be a string with one letter for each facet, in the same order as their Facet ID. `n` is used to indicate neither reachable nor recognizable. For example, a value of `rsnr` means there are four facets, the first (`o+d12/1:0`) and last (`o+d12/1:3`) are reachable, the second (`o+d12/1:1`) is recognizable, and the third (`o+d12/1:2`) is neither.
93
+
94
+
95
+ # Durable Kinds
96
+
97
+ Virtual objects are held on disk, which makes them suitable for high-cardinality data that is likely too large for our vat workers' limited RAM budget: many objects, most of which are "idle" at any given time. However virtual objects do not survive a vat upgrade. For this, vats should define one or more "Durable Kinds" instead.
98
+
99
+ Durable Kinds are defined just like virtual Kinds, but they use a different constructor (`defineDurableKind` instead of `defineKind`), which requires a "handle" created by `makeKindHandle`. Durable virtual objects can only hold durable data in their `state`.
100
+
101
+ The KindHandle is a durable virtual object of a special internal Kind. This is the first Kind allocated, so usually it gets exportID 1 to use as a Kind ID, and the kind handles for virtual and durable Kinds get vrefs like `o+d1/${kindHandleID}`.
102
+
103
+
104
+ # Kind Metadata
105
+
106
+ For each virtual object kind that is defined, we store a metadata record for purposes of scanning directly through the defined kinds when a vat is stopped or upgraded. For durable kinds this record is stored in `vom.dkind.${kindID}.descriptor`; for non-durable kinds it is stored in `vom.vkind.${kindID}.descriptor`. Currently this metadata takes the form of a JSON-serialized record with the following properties:
107
+ * `kindID`, the kind ID as a numeric string (redundantly with the storage key)
108
+ * `tag`, the tag string as provided in the `defineKind` or `makeKindHandle` call
109
+ * `nextInstanceID`, an integer that is present only for durable kinds. It ensures that all versions share a single sequence of unique instance IDs. `nextInstanceID` is added to the metadata record upon allocation of the first instance of the kind and updated after each subsequent allocation.
110
+ * `unfaceted`, a property with boolean value `true` that is present only for single-facet durable kinds.
111
+ * `facets`, an array that is present only for multi-facet durable kinds. Its elements are the names of the kind's facets, in the same order as the assignment of facet indices within the cohort record.
112
+ * `stateShapeCapData`, a property with a `{ body, slots }` CapData record that decodes into `undefined`, or else into a CopyRecord [Pattern](https://www.npmjs.com/package/@endo/patterns) for constraining instance `state` records.
113
+
114
+ `unfaceted` and `facets` are required so that kind definitions in upgraded versions of the containing vat are maintained in a backwards compatible manner over time.
115
+
116
+ # Virtual/Durable Collections (aka Stores)
117
+
118
+ Liveslots provides vats with a handful of "virtual collection" types for storing high-cardinality data on disk rather than in RAM. Each instance of one of these types is described as a "[Store](../../store/docs/store-taxonomy.md)". They provide limited range queries and offer a single fixed sort index: numbers sort as usual, BigInts sort as usual but separate from numbers, strings sort lexicographically by UTF-8 encoding, and object references sort by insertion order.
119
+
120
+ Collections are created by functions on the `VatStore` global:
121
+
122
+ * `makeScalarBigMapStore`
123
+ * `makeScalarBigWeakMapStore`
124
+ * `makeScalarBigSetStore`
125
+ * `makeScalarBigWeakSetStore`
126
+
127
+ Each function accepts a boolean `durable` option, so there are currently 8 collection types.
128
+
129
+ Each collection type is assigned a Kind index, just like the user-defined Kinds. The 8 collection types are allocated before userspace gets a chance to call `defineKind` or `defineDurableKind`, so they claim earlier exportID numbers as described [above](#counters).
130
+
131
+ These index values are stored in `storeKindIDTable`, as a mapping from the collection type name ("scalarMapStore", "scalarDurableMapStore", "scalarWeakSetStore", etc.) to the integer of their ID. The current table assignments are:
132
+
133
+ * `v6.vs.storeKindIDTable` : `{"scalarMapStore":2,"scalarWeakMapStore":3,"scalarSetStore":4,"scalarWeakSetStore":5,"scalarDurableMapStore":6,"scalarDurableWeakMapStore":7,"scalarDurableSetStore":8,"scalarDurableWeakSetStore":9}`
134
+
135
+ which means `2` is the Kind ID for non-durable merely-virtual "scalarMapStore", instances of which will have vrefs like `o+v2/${collectionID}`.
136
+
137
+ Each new store, regardless of type, is allocated the next available collectionID [counter](#counters). This is an incrementing integer that starts at 1, and forms a numberspace independent of the exportID counter used by exported Remotables and Kind IDs. The same collectionID numberspace is shared by all collection types. So unlike virtual objects (where the instanceID in `o+v${kindID}/${instanceID}` is scoped to `o+v${kindID}`), for collections the collectionID in `o+v${collectionType}/${collectionID}` is global to the entire vat. No two stores will have the same collectionID, even if they are of different types.
138
+
139
+ The interpretation of a vref therefore varies based on whether the initial "type" portion before a slash (`o+v${exportID}` or `o+d${exportID}`) identifies a collection type or a virtual object kind:
140
+
141
+ * `o+d6/1`: `6` is a collection type in the storeKindIDTable ("scalarDurableMapStore"), so `o+d6/1` refers to the first collection (of any type) in the vat
142
+ * `o+d7/1`: `7` is also a collection type in the storeKindIDTable ("scalarDurableWeakMapStore"), so `o+d7/1` is guaranteed not to coexist with `o+d6/1`
143
+ * `o+d7/2`: refers to the second collection (of any type) in the vat, which has type `7` ("scalarDurableWeakMapStore")
144
+ * `o+v5/3`: refers to the third collection (of any type) in the vat, which has type `5` ("scalarWeakSetStore")
145
+ * `o+v5/4`: refers to the fourth collection (of any type) in the vat, also a scalarWeakSetStore
146
+ * `o+v11/1`: `11` is not a collection type in the storeKindIDTable, so is instead a kind and `o+v11/1` refers to the first instance of that kind
147
+ * `o+v11/2`: refers to the second instance of that kind
148
+
149
+
150
+ # Baggage
151
+
152
+ Most collections are created by userspace code, but to support vat upgrade, liveslots creates one special collection named "baggage". This is a `scalarDurableMapStore` that is passed into the third argument of `buildRootObject`.
153
+
154
+ This object needs to be pre-generated because the second (and subsequent) versions of the vat will use it to reach all other durable objects from their predecessors, so v2 can remember things that were stored by v1. The most significant values of "baggage" are the KindHandles for durable Kinds made by v1. V2 will need these to call `defineDurableKind` and re-attach behavior for each one. Each version must re-attach behavior for *all* durable Kinds created by its predecessors.
155
+
156
+ The above rules about kindID and collectionID allocation result in the baggage being associated with vref `o+d6/1`, indicating that it is a scalarDurableMapStore (`o+d6` is used for that collection type) and also that it is the first collection of any type allocated in the vat. This value is also stored under key `baggageID` (see `provideBaggage` in [collectionManager.js](./collectionManager.js)).
157
+ * `v6.vs.baggageID` : `o+d6/1`
158
+
159
+ If userspace version 1 starts `buildRootObject` by calling `makeScalarBigWeakSetStore()` and then three `makeScalarSetStore()`s, the collections are likely to be assigned `o+v5/2`, `o+v4/3`, `o+v4/4`, and `o+v4/5` respectively. Such collectionIDs start with `2` because `1` is claimed by baggage.
160
+
161
+
162
+ # Collection Data Records
163
+
164
+ We examine a vat which performs the following at startup:
165
+
166
+ ```js
167
+ const initFoo = arg => ({ prop1: arg });
168
+ const fooBehavior = {
169
+ getProp1: ({ state }) => state.prop1,
170
+ };
171
+ const makeFoo = VatData.defineKind('foo', initFoo, fooBehavior);
172
+ const foo = makeFoo(1);
173
+ const foo2 = makeFoo(2);
174
+ const c1 = VatData.makeScalarBigMapStore('mylabel');
175
+ c1.init('key1', foo);
176
+ c1.init('key2', foo);
177
+ c1.init('key3', foo);
178
+ c1.init('key4', foo2);
179
+ ```
180
+
181
+ Each collection stores a number of metadata keys in the vatstore, all with a prefix of `vc.${collectionID}.|` (note that the collection *type* is not a part of the key, only the collection *index*). The currently defined metadata keys (copied from the record for the "mylabel" Kind stored in `c1`) are:
182
+
183
+ * `v6.vs.vc.2.|entryCount`: `4` (the size of the collection as a numeric string, incremented with each call to `c1.init` and decremented with each call to `c1.delete`)
184
+ * `v6.vs.vc.2.|nextOrdinal`: `1` (a numeric string counter used to allocate index values for Objects used as keys, see `generateOrdinal` in [collectionManager.js](./collectionManager.js))
185
+ * `v6.vs.vc.2.|schemata`: `{"label":"mylabel","body":"#[{\\"#tag\\":\\"match:scalar\\",\\"payload\\":\\"#undefined\\"}]","slots":[]}`
186
+
187
+ The `schemata` is a capdata serialization of the debugging label provided in the `make*Store` call that created the collection, plus the Matcher constraints recorded for the collection. These constraints can limit keys to be just strings, or numbers, etc. (see [Patterns](https://github.com/endojs/endo/tree/master/packages/patterns)). The schemata consists of an array in which the first element is a schema for the keys and the second is a separate schema for the values.
188
+
189
+ Each entry in the collection gets put into a single vatstore entry with a capdata-serialized value:
190
+
191
+ * `v6.vs.vc.2.skey1`: `{"body":"#\"$0.Alleged: foo\"","slots":["o+d9/1"]}`
192
+ * `v6.vs.vc.2.skey2`: `{"body":"#\"$0.Alleged: foo\"","slots":["o+d9/1"]}`
193
+ * `v6.vs.vc.2.skey3`: `{"body":"#\"$0.Alleged: foo\"","slots":["o+d9/1"]}`
194
+ * `v6.vs.vc.2.skey4`: `{"body":"#\"$0.Alleged: foo\"","slots":["o+d9/2"]}`
195
+
196
+ The key string for each entry (e.g. `skey1`) is formed by serializing the key object. Strings get a simple `s` prefix. Other objects use more complex encodings, designed to allow numbers (floats and BigInts, separately) to sort numerically despite the kvStore keys sorting lexicographically. See Endo [encodePassable.js](https://github.com/endojs/endo/blob/master/packages/marshal/src/encodePassable.js) for details. Object references involve an additional kvStore entry, to manage the mapping from Object to ordinal and back.
197
+
198
+ For weak stores, the collection manager also maintains inbound-reference database keys of the form `vom.ir.${vref}|${collectionID}`, where in this case `${vref}` is the vref of a virtual object, store, import, or remotable, and `${collectionID}` is the collectionID of a weak store in which the given vref is used as a key. This enables the collection manager to locate and remove collection entries whose keys are being garbage collected. Note that mere presence or absence of such a key in the database is significant but the value associated with it is not.
@@ -0,0 +1,44 @@
1
+ export function makeVirtualObjectManager(syscall: any, vrm: import("./virtualReferences.js").VirtualReferenceManager, allocateExportID: () => number, getSlotForVal: (val: object) => string | undefined, requiredValForSlot: (slot: string) => object, registerValue: any, serialize: ToCapData<string>, unserialize: FromCapData<string>, assertAcceptableSyscallCapdataSize: any, liveSlotsOptions?: import("./types.js").LiveSlotsOptions, { WeakMap, WeakSet }?: {
2
+ WeakMap: typeof globalThis.WeakMap;
3
+ WeakSet: typeof globalThis.WeakSet;
4
+ }): {
5
+ initializeKindHandleKind: () => void;
6
+ defineKind: <P extends Array<any>, S, F>(tag: string, init: (...args: P) => S, facet: F, options?: DefineKindOptions<import("@agoric/swingset-liveslots").KindContext<S, F>>) => (...args: P) => import("@agoric/swingset-liveslots").KindFacet<F>;
7
+ defineKindMulti: <P extends Array<any>, S, B>(tag: string, init: (...args: P) => S, behavior: B, options?: DefineKindOptions<import("@agoric/swingset-liveslots").MultiKindContext<S, B>>) => (...args: P) => import("@agoric/swingset-liveslots").KindFacets<B>;
8
+ defineDurableKind: <P extends Array<any>, S, F>(kindHandle: DurableKindHandle, init: (...args: P) => S, facet: F, options?: DefineKindOptions<import("@agoric/swingset-liveslots").KindContext<S, F>>) => (...args: P) => import("@agoric/swingset-liveslots").KindFacet<F>;
9
+ defineDurableKindMulti: <P extends Array<any>, S, B>(kindHandle: DurableKindHandle, init: (...args: P) => S, behavior: B, options?: DefineKindOptions<import("@agoric/swingset-liveslots").MultiKindContext<S, B>>) => (...args: P) => import("@agoric/swingset-liveslots").KindFacets<B>;
10
+ makeKindHandle: (tag: string) => DurableKindHandle;
11
+ insistAllDurableKindsReconnected: () => void;
12
+ VirtualObjectAwareWeakMap: {
13
+ new (): {
14
+ has(key: any): any;
15
+ get(key: any): any;
16
+ set(key: any, value: any): /*elided*/ any;
17
+ delete(key: any): any;
18
+ };
19
+ };
20
+ VirtualObjectAwareWeakSet: {
21
+ new (): {
22
+ has(value: any): any;
23
+ add(value: any): /*elided*/ any;
24
+ delete(value: any): any;
25
+ };
26
+ };
27
+ flushStateCache: () => void;
28
+ getRetentionStats: () => {
29
+ definedDurableKinds: number;
30
+ nextInstanceIDs: number;
31
+ };
32
+ testHooks: {
33
+ countWeakKeysForCollection: (collection: any) => any;
34
+ definedDurableKinds: Set<any>;
35
+ nextInstanceIDs: Map<any, any>;
36
+ };
37
+ canBeDurable: (specimen: any) => boolean;
38
+ };
39
+ export type VirtualObjectManager = ReturnType<typeof makeVirtualObjectManager>;
40
+ import type { ToCapData } from '@endo/marshal';
41
+ import type { FromCapData } from '@endo/marshal';
42
+ import type { DefineKindOptions } from '@agoric/swingset-liveslots';
43
+ import type { DurableKindHandle } from '@agoric/swingset-liveslots';
44
+ //# sourceMappingURL=virtualObjectManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"virtualObjectManager.d.ts","sourceRoot":"","sources":["virtualObjectManager.js"],"names":[],"mappings":"AAiWO,kDApDI,GAAC,OACD,OAAO,wBAAwB,EAAE,uBAAuB,oBAExD,MAAM,MAAM,iBAEZ,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,sBAGnC,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,iBACxB,GAAC,aAED,UAAU,MAAM,CAAC,eACjB,YAAY,MAAM,CAAC,sCACnB,GAAC,qBAED,OAAO,YAAY,EAAE,gBAAgB,yBACrC;IAAE,OAAO,EAAE,yBAAc,CAAC;IAAC,OAAO,EAAE,yBAAc,CAAA;CAAE;;iEA3KtB,GAAG,kHA+C5C,GA5CG;sEAIe,GAAE,0HAEb,GAAG;0FAK4C,GAAG,kHACU,GAAG;+FAKhC,GAAG,0HACgB,GAAG;0BA6lC/C,MAAM,KACJ,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqI/B;mCAEa,UAAU,CAAC,OAAO,wBAAwB,CAAC;+BAt3ChB,eAAe;iCAAf,eAAe;uCAFpB,4BAA4B;uCAD5B,4BAA4B"}