@agoric/swingset-vat 0.32.3-dev-657b621.0 → 0.32.3-dev-696f0a8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +13 -12
  2. package/tools/baggage-check.js +194 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agoric/swingset-vat",
3
- "version": "0.32.3-dev-657b621.0+657b621",
3
+ "version": "0.32.3-dev-696f0a8.0+696f0a8",
4
4
  "description": "Vat/Container Launcher",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -28,16 +28,16 @@
28
28
  "yargs-parser": "^21.1.1"
29
29
  },
30
30
  "dependencies": {
31
- "@agoric/assert": "0.6.1-dev-657b621.0+657b621",
32
- "@agoric/internal": "0.3.3-dev-657b621.0+657b621",
33
- "@agoric/store": "0.9.3-dev-657b621.0+657b621",
34
- "@agoric/swing-store": "0.9.2-dev-657b621.0+657b621",
35
- "@agoric/swingset-liveslots": "0.10.3-dev-657b621.0+657b621",
36
- "@agoric/swingset-xsnap-supervisor": "0.10.3-dev-657b621.0+657b621",
37
- "@agoric/time": "0.3.3-dev-657b621.0+657b621",
38
- "@agoric/vat-data": "0.5.3-dev-657b621.0+657b621",
39
- "@agoric/xsnap": "0.14.3-dev-657b621.0+657b621",
40
- "@agoric/xsnap-lockdown": "0.14.1-dev-657b621.0+657b621",
31
+ "@agoric/assert": "0.6.1-dev-696f0a8.0+696f0a8",
32
+ "@agoric/internal": "0.3.3-dev-696f0a8.0+696f0a8",
33
+ "@agoric/store": "0.9.3-dev-696f0a8.0+696f0a8",
34
+ "@agoric/swing-store": "0.9.2-dev-696f0a8.0+696f0a8",
35
+ "@agoric/swingset-liveslots": "0.10.3-dev-696f0a8.0+696f0a8",
36
+ "@agoric/swingset-xsnap-supervisor": "0.10.3-dev-696f0a8.0+696f0a8",
37
+ "@agoric/time": "0.3.3-dev-696f0a8.0+696f0a8",
38
+ "@agoric/vat-data": "0.5.3-dev-696f0a8.0+696f0a8",
39
+ "@agoric/xsnap": "0.14.3-dev-696f0a8.0+696f0a8",
40
+ "@agoric/xsnap-lockdown": "0.14.1-dev-696f0a8.0+696f0a8",
41
41
  "@endo/base64": "^0.2.31",
42
42
  "@endo/bundle-source": "^2.5.1",
43
43
  "@endo/captp": "^3.1.1",
@@ -54,6 +54,7 @@
54
54
  "@endo/zip": "^0.2.31",
55
55
  "ansi-styles": "^6.2.1",
56
56
  "anylogger": "^0.21.0",
57
+ "better-sqlite3": "^8.2.0",
57
58
  "import-meta-resolve": "^2.2.1",
58
59
  "microtime": "^3.1.0",
59
60
  "semver": "^6.3.0",
@@ -92,5 +93,5 @@
92
93
  "publishConfig": {
93
94
  "access": "public"
94
95
  },
95
- "gitHead": "657b6210ee039ae55a63d472e2cf9adc9fa15650"
96
+ "gitHead": "696f0a8c4925c8a40f415c16536568fc4e8008c8"
96
97
  }
@@ -0,0 +1,194 @@
1
+ import { makeMarshal } from '@endo/marshal';
2
+ import { Far } from '@endo/far';
3
+
4
+ /* eslint-disable no-use-before-define */
5
+
6
+ function fakeSTV(slot, iface = 'Remotable') {
7
+ return Far(iface, {
8
+ getSlot: () => slot,
9
+ });
10
+ }
11
+
12
+ const marshaller = makeMarshal(undefined, fakeSTV, {
13
+ serializeBodyFormat: 'smallcaps',
14
+ });
15
+ const { fromCapData } = marshaller;
16
+
17
+ function decodeValueString(s) {
18
+ const parsed = JSON.parse(s);
19
+ const value = fromCapData(parsed);
20
+ return [value, parsed.slots];
21
+ }
22
+
23
+ function extractDurableRefParts(ref) {
24
+ const patt = /^o\+d([0-9]+)\/([0-9]+)$/;
25
+ const matches = ref.match(patt);
26
+ if (matches) {
27
+ return [+matches[1], +matches[2]];
28
+ } else {
29
+ return null;
30
+ }
31
+ }
32
+
33
+ export function checkBaggage(db, vatID, verbose = false) {
34
+ const sqlKVDump = db.prepare(`
35
+ SELECT key, value
36
+ FROM kvStore
37
+ WHERE key GLOB ?
38
+ `);
39
+
40
+ const sqlKVGet = db.prepare(`
41
+ SELECT value
42
+ FROM kvStore
43
+ WHERE key = ?
44
+ `);
45
+ sqlKVGet.pluck(true);
46
+
47
+ const vatStoreKeyRoot = `${vatID}.vs`;
48
+ const vomKeyRoot = `${vatStoreKeyRoot}.vom`;
49
+ const dkindKeyRoot = `${vomKeyRoot}.dkind`;
50
+ const vcKeyRoot = `${vatStoreKeyRoot}.vc`;
51
+
52
+ // Kinds which are known to have definitions. Initially these are just those
53
+ // whose definitions are built in.
54
+ const predefinedKinds = new Map(); // kindID -> tag
55
+
56
+ predefinedKinds.set(1, 'kindHandle');
57
+ const builtInKinds = JSON.parse(
58
+ sqlKVGet.get(`${vatStoreKeyRoot}.storeKindIDTable`),
59
+ );
60
+ for (const kindName of Object.keys(builtInKinds)) {
61
+ predefinedKinds.set(builtInKinds[kindName], kindName);
62
+ }
63
+ const KIND_HANDLE_BASEREF = 1;
64
+ const BIGMAP_BASEREF = 6;
65
+ const BIGSET_BASEREF = 8;
66
+
67
+ // Kinds for which we have seen a kindHandle entry in the vatStore. These are
68
+ // kinds which exist and have been used at some point, though their current
69
+ // ontological status is unknown.
70
+ const extantKinds = new Map(); // kindID -> tag
71
+
72
+ // Kinds for which we have seen a kindHandle value reference in the reference
73
+ // graph descended from baggage. These are kinds that are potentially
74
+ // definable, though we can't at this stage determine if they've actually been
75
+ // given definitions.
76
+ const knownKinds = new Set();
77
+
78
+ // Kinds that have been seen in use somewhere. These are kinds that had
79
+ // better have definitions or else something Bad will happen.
80
+ const usedKinds = new Set();
81
+
82
+ const kindKVs = sqlKVDump.iterate(`${dkindKeyRoot}.*`);
83
+ for (const kv of kindKVs) {
84
+ const descriptorSuffix = '.descriptor';
85
+ if (kv.key.endsWith(descriptorSuffix)) {
86
+ const dkindID = kv.key
87
+ .substring(0, kv.key.length - descriptorSuffix.length)
88
+ .substring(dkindKeyRoot.length + 1);
89
+ const descriptor = JSON.parse(kv.value);
90
+ extantKinds.set(+dkindID, descriptor.tag);
91
+ }
92
+ }
93
+
94
+ let pendingCollections = new Set();
95
+ const knownCollections = new Set();
96
+ let pendingObjects = new Set();
97
+ const knownObjects = new Set();
98
+
99
+ pendingCollections.add(1);
100
+ do {
101
+ const workingCollections = pendingCollections;
102
+ pendingCollections = new Set();
103
+ for (const coll of workingCollections) {
104
+ knownCollections.add(coll);
105
+ }
106
+ for (const coll of workingCollections) {
107
+ scanCollection(coll);
108
+ }
109
+ const workingObjects = pendingObjects;
110
+ pendingObjects = new Set();
111
+ for (const obj of workingObjects) {
112
+ knownObjects.add(obj);
113
+ }
114
+ for (const obj of workingObjects) {
115
+ scanObject(obj);
116
+ }
117
+ } while (pendingCollections.size > 0 || pendingObjects.size > 0);
118
+
119
+ // Kinds which have been used but whose kindID handles have not been seen
120
+ const usedButNotKnownKinds = new Set();
121
+ usedKinds.forEach(v => usedButNotKnownKinds.add(v));
122
+ knownKinds.forEach(v => usedButNotKnownKinds.delete(v));
123
+
124
+ // Kinds which exist but whose kind handles have not been seen
125
+ const extantButNotSeen = new Map();
126
+ extantKinds.forEach((k, v) => extantButNotSeen.set(v, k));
127
+ knownKinds.forEach(k => extantButNotSeen.delete(k));
128
+
129
+ // Kinds which exist but are not used
130
+ const extantButNotUsed = new Map();
131
+ extantKinds.forEach((k, v) => extantButNotUsed.set(v, k));
132
+ usedKinds.forEach(k => extantButNotUsed.delete(k));
133
+
134
+ if (verbose || usedButNotKnownKinds.size > 0) {
135
+ console.log('predefinedKinds', predefinedKinds);
136
+ console.log('extantKinds', extantKinds);
137
+ console.log('knownKinds', knownKinds);
138
+ console.log('usedKinds', usedKinds);
139
+ console.log('extantButNotSeen', extantButNotSeen);
140
+ console.log('extantButNotUsed', extantButNotUsed);
141
+ console.log('usedButNotKnownKinds', usedButNotKnownKinds);
142
+ }
143
+ if (usedButNotKnownKinds.size > 0) {
144
+ throw Error(
145
+ `kind IDs used without reachable kind ID handles: ${usedButNotKnownKinds.size}`,
146
+ );
147
+ }
148
+
149
+ function scanSlots(slots) {
150
+ for (const slot of slots) {
151
+ const refParts = extractDurableRefParts(slot);
152
+ if (refParts) {
153
+ const [baseRef, subRef] = refParts;
154
+ if (baseRef === BIGMAP_BASEREF || baseRef === BIGSET_BASEREF) {
155
+ if (!knownCollections.has(subRef)) {
156
+ pendingCollections.add(subRef);
157
+ }
158
+ } else if (baseRef === KIND_HANDLE_BASEREF) {
159
+ knownKinds.add(subRef);
160
+ } else {
161
+ if (!usedKinds.has(baseRef)) {
162
+ usedKinds.add(baseRef);
163
+ }
164
+ if (!knownObjects.has(slot)) {
165
+ pendingObjects.add(slot);
166
+ }
167
+ }
168
+ }
169
+ }
170
+ }
171
+
172
+ function scanCollection(collectionID) {
173
+ const collectionKeyRoot = `${vcKeyRoot}.${collectionID}.`;
174
+ const keyMatch = `${collectionKeyRoot}[a-z]*`;
175
+ const kvPairs = sqlKVDump.iterate(keyMatch);
176
+ for (const kv of kvPairs) {
177
+ const key = kv.key.substring(collectionKeyRoot.length);
178
+ const [_, slots] = decodeValueString(kv.value);
179
+ if (key[0] === 'r') {
180
+ const rkey = key.split(':')[1];
181
+ scanSlots([rkey]);
182
+ }
183
+ scanSlots(slots);
184
+ }
185
+ }
186
+
187
+ function scanObject(objectID) {
188
+ const rawObj = sqlKVGet.get(`${vomKeyRoot}.${objectID}`);
189
+ const props = JSON.parse(rawObj);
190
+ for (const prop of Object.keys(props)) {
191
+ scanSlots(props[prop].slots);
192
+ }
193
+ }
194
+ }