@agoric/swing-store 0.9.2-dev-7244c71.0 → 0.9.2-getting-started-dev-26244e8.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.
- package/CHANGELOG.md +38 -0
- package/docs/data-export.md +51 -78
- package/{tsconfig.json → jsconfig.json} +0 -4
- package/package.json +11 -17
- package/src/bundleStore.js +1 -0
- package/src/snapStore.js +1 -1
- package/src/swingStore.js +0 -5
- package/test/test-bundles.js +1 -0
- package/test/test-deletion.js +1 -0
- package/test/test-export.js +2 -0
- package/test/test-exportImport.js +7 -1
- package/test/test-hasher.js +1 -0
- package/test/test-import.js +104 -9
- package/test/test-repair-metadata.js +3 -1
- package/test/test-snapstore.js +5 -0
- package/test/test-state.js +3 -1
- package/test/exports.js +0 -99
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,44 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
### [0.9.2-u12.0](https://github.com/Agoric/agoric-sdk/compare/@agoric/swing-store@0.9.2-u11wf.0...@agoric/swing-store@0.9.2-u12.0) (2023-11-10)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **swing-store:** faster import of swing-store ([35aef87](https://github.com/Agoric/agoric-sdk/commit/35aef87ec0f10b7f0cdce462ac0509296e8bd752))
|
|
12
|
+
* **swing-store:** prevent SwingSet usage of imported swing-store ([03f642d](https://github.com/Agoric/agoric-sdk/commit/03f642d39f90ef9465a439723c3a69beef73bd61))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* **swing-store:** ensure crank savepoint is wrapped in transaction ([8d738c6](https://github.com/Agoric/agoric-sdk/commit/8d738c65ed37b9159e94fbcf291ed7fe8478ee5a))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### [0.9.2-u11wf.0](https://github.com/Agoric/agoric-sdk/compare/@agoric/swing-store@0.9.2-u11.0...@agoric/swing-store@0.9.2-u11wf.0) (2023-09-23)
|
|
22
|
+
|
|
23
|
+
**Note:** Version bump only for package @agoric/swing-store
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
### [0.9.2-u11.0](https://github.com/Agoric/agoric-sdk/compare/@agoric/swing-store@0.9.1...@agoric/swing-store@0.9.2-u11.0) (2023-08-24)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
### Features
|
|
33
|
+
|
|
34
|
+
* **swingstore:** add repairMetadata() ([5b2d19d](https://github.com/Agoric/agoric-sdk/commit/5b2d19d1153a23c118afb14ca4ed80e175640f62)), closes [#8025](https://github.com/Agoric/agoric-sdk/issues/8025) [#8025](https://github.com/Agoric/agoric-sdk/issues/8025)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
### Bug Fixes
|
|
38
|
+
|
|
39
|
+
* **swing-store:** add 'replay' artifactMode, make export more strict ([d46c8e2](https://github.com/Agoric/agoric-sdk/commit/d46c8e2d270999ccba552e0072cb5e0926922f28)), closes [#8105](https://github.com/Agoric/agoric-sdk/issues/8105)
|
|
40
|
+
* rewrite importSwingStore to preserve metadata properly ([03e323a](https://github.com/Agoric/agoric-sdk/commit/03e323a55ffeb98dcc84a57050a5d3fc881899b8)), closes [#8025](https://github.com/Agoric/agoric-sdk/issues/8025)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
6
44
|
### [0.9.1](https://github.com/Agoric/agoric-sdk/compare/@agoric/swing-store@0.9.0...@agoric/swing-store@0.9.1) (2023-06-02)
|
|
7
45
|
|
|
8
46
|
**Note:** Version bump only for package @agoric/swing-store
|
package/docs/data-export.md
CHANGED
|
@@ -39,41 +39,30 @@ The exporter is created by calling `makeSwingStoreExporter(dirpath)`, passing it
|
|
|
39
39
|
After calling `hostStorage.commit()`, the host application can extract the first-stage export data, and then the second-stage export artifacts:
|
|
40
40
|
|
|
41
41
|
```js
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
child
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
42
|
+
import { buffer } from 'node:stream/consumers';
|
|
43
|
+
|
|
44
|
+
const dirPath = '.../swing-store';
|
|
45
|
+
const swingStore = openSwingStore(dirPath);
|
|
46
|
+
...
|
|
47
|
+
await controller.run();
|
|
48
|
+
hostStorage.commit();
|
|
49
|
+
// spawn a child process
|
|
50
|
+
|
|
51
|
+
// child process does:
|
|
52
|
+
const exporter = makeSwingStoreExporter(dirPath);
|
|
53
|
+
// exporter now has a txn, parent process is free to proceed forward
|
|
54
|
+
const exportData = new Map();
|
|
55
|
+
for (const [key, value] of exporter.getExportData()) {
|
|
56
|
+
exportData.set(key, value);
|
|
55
57
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
//
|
|
64
|
-
process.send({ type: 'started' });
|
|
65
|
-
const exportData = new Map();
|
|
66
|
-
for (const [key, value] of exporter.getExportData()) {
|
|
67
|
-
exportData.set(key, value);
|
|
68
|
-
}
|
|
69
|
-
const exportArtifacts = new Map();
|
|
70
|
-
for (const name of exporter.getArtifactNames()) {
|
|
71
|
-
const reader = exporter.getArtifact(name);
|
|
72
|
-
// reader is an async iterable of Uint8Array, e.g. a stream
|
|
73
|
-
const data = await buffer(reader);
|
|
74
|
-
exportArtifacts.set(name, data);
|
|
75
|
-
}
|
|
76
|
-
// export is the combination of 'exportData' and 'exportArtifacts'
|
|
58
|
+
const exportArtifacts = new Map();
|
|
59
|
+
for (const name of exporter.getArtifactNames()) {
|
|
60
|
+
const reader = exporter.getArtifact(name);
|
|
61
|
+
// reader is an async iterable of Uint8Array, e.g. a stream
|
|
62
|
+
const data = await buffer(reader);
|
|
63
|
+
exportArtifacts.set(name, data);
|
|
64
|
+
}
|
|
65
|
+
// export is 'exportData' and 'exportArtifacts'
|
|
77
66
|
```
|
|
78
67
|
|
|
79
68
|

|
|
@@ -103,51 +92,35 @@ Then, on the few occasions when the application needs to build a full state-sync
|
|
|
103
92
|

|
|
104
93
|
|
|
105
94
|
```js
|
|
106
|
-
const dirPath = '.../swing-store';
|
|
107
|
-
const iavl = ...;
|
|
108
|
-
function exportCallback(key, value) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
const swingStore = openSwingStore(dirPath, { exportCallback });
|
|
117
|
-
...
|
|
118
|
-
await controller.run();
|
|
119
|
-
hostStorage.commit();
|
|
120
|
-
|
|
121
|
-
// now, if the validator is configured to publish state-sync snapshots,
|
|
122
|
-
// and if this block height is one of the publishing points,
|
|
123
|
-
// do the following:
|
|
124
|
-
|
|
125
|
-
// spawn a child process
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
95
|
+
const dirPath = '.../swing-store';
|
|
96
|
+
const iavl = ...;
|
|
97
|
+
function exportCallback(key, value) {
|
|
98
|
+
const iavlKey = `ssed.${key}`; // 'ssed' is short for SwingStoreExportData
|
|
99
|
+
if (value) {
|
|
100
|
+
iavl.set(iavlKey, value);
|
|
101
|
+
} else {
|
|
102
|
+
iavl.delete(iavlKey); // value===undefined means delete
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const swingStore = openSwingStore(dirPath, { exportCallback });
|
|
106
|
+
...
|
|
107
|
+
await controller.run();
|
|
108
|
+
hostStorage.commit();
|
|
109
|
+
|
|
110
|
+
// now, if the validator is configured to publish state-sync snapshots,
|
|
111
|
+
// and if this block height is one of the publishing points,
|
|
112
|
+
// do the following:
|
|
113
|
+
|
|
114
|
+
// spawn a child process
|
|
115
|
+
|
|
116
|
+
// child process does:
|
|
117
|
+
const exporter = makeSwingStoreExporter(dirPath);
|
|
118
|
+
// note: no exporter.getExportData(), the first-stage data is already in IAVL
|
|
119
|
+
const artifacts = new Map();
|
|
120
|
+
for (const name of exporter.getArtifactNames()) {
|
|
121
|
+
artifacts.set(name, exporter.getArtifact(name));
|
|
133
122
|
}
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
await started.promise;
|
|
137
|
-
} catch (err) {
|
|
138
|
-
...
|
|
139
|
-
}
|
|
140
|
-
...
|
|
141
|
-
|
|
142
|
-
// child process does:
|
|
143
|
-
const exporter = makeSwingStoreExporter(dirPath);
|
|
144
|
-
process.send({ type: 'started' });
|
|
145
|
-
// note: no exporter.getExportData(), the first-stage data is already in IAVL
|
|
146
|
-
const artifacts = new Map();
|
|
147
|
-
for (const name of exporter.getArtifactNames()) {
|
|
148
|
-
artifacts.set(name, exporter.getArtifact(name));
|
|
149
|
-
}
|
|
150
|
-
// instruct cosmos-sdk to include 'artifacts' in the state-sync snapshot
|
|
123
|
+
// instruct cosmos-sdk to include 'artifacts' in the state-sync snapshot
|
|
151
124
|
```
|
|
152
125
|
|
|
153
126
|
## Import
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/swing-store",
|
|
3
|
-
"version": "0.9.2-dev-
|
|
3
|
+
"version": "0.9.2-getting-started-dev-26244e8.0+26244e8",
|
|
4
4
|
"description": "Persistent storage for SwingSet",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -17,22 +17,22 @@
|
|
|
17
17
|
"test:xs": "exit 0",
|
|
18
18
|
"lint-fix": "yarn lint:eslint --fix",
|
|
19
19
|
"lint": "run-s --continue-on-error lint:*",
|
|
20
|
-
"lint:types": "tsc",
|
|
20
|
+
"lint:types": "tsc -p jsconfig.json",
|
|
21
21
|
"lint:eslint": "eslint ."
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@agoric/assert": "0.6.1-dev-
|
|
25
|
-
"@agoric/internal": "0.
|
|
26
|
-
"@endo/base64": "
|
|
27
|
-
"@endo/bundle-source": "
|
|
28
|
-
"@endo/check-bundle": "
|
|
29
|
-
"@endo/nat": "
|
|
24
|
+
"@agoric/assert": "0.6.1-getting-started-dev-26244e8.0+26244e8",
|
|
25
|
+
"@agoric/internal": "0.4.0-getting-started-dev-26244e8.0+26244e8",
|
|
26
|
+
"@endo/base64": "0.2.31",
|
|
27
|
+
"@endo/bundle-source": "2.5.2-upstream-rollup",
|
|
28
|
+
"@endo/check-bundle": "0.2.18",
|
|
29
|
+
"@endo/nat": "4.1.27",
|
|
30
30
|
"better-sqlite3": "^8.2.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@endo/init": "
|
|
33
|
+
"@endo/init": "0.5.56",
|
|
34
34
|
"@types/better-sqlite3": "^7.5.0",
|
|
35
|
-
"ava": "^5.
|
|
35
|
+
"ava": "^5.2.0",
|
|
36
36
|
"c8": "^7.13.0",
|
|
37
37
|
"tmp": "^0.2.1"
|
|
38
38
|
},
|
|
@@ -43,13 +43,7 @@
|
|
|
43
43
|
"files": [
|
|
44
44
|
"test/**/test-*.js"
|
|
45
45
|
],
|
|
46
|
-
"require": [
|
|
47
|
-
"@endo/init/debug.js"
|
|
48
|
-
],
|
|
49
46
|
"timeout": "2m"
|
|
50
47
|
},
|
|
51
|
-
"
|
|
52
|
-
"atLeast": 75.52
|
|
53
|
-
},
|
|
54
|
-
"gitHead": "7244c710962174a886903cf039c0fbe18874287f"
|
|
48
|
+
"gitHead": "26244e821f1a83cd5868f0c7d54aa480c8c17e5e"
|
|
55
49
|
}
|
package/src/bundleStore.js
CHANGED
|
@@ -328,6 +328,7 @@ export function makeBundleStore(db, ensureTxn, noteExport = () => {}) {
|
|
|
328
328
|
endoZipBase64: encodeBase64(data),
|
|
329
329
|
});
|
|
330
330
|
// Assert that the bundle contents match the ID and hash
|
|
331
|
+
// eslint-disable-next-line @jessie.js/no-nested-await
|
|
331
332
|
await checkBundle(bundle, computeSha512, bundleID);
|
|
332
333
|
populateBundle(bundleID, serializeBundle(bundleID, bundle));
|
|
333
334
|
} else {
|
package/src/snapStore.js
CHANGED
|
@@ -333,11 +333,11 @@ export function makeSnapStore(
|
|
|
333
333
|
snapReader.pipe(hashStream);
|
|
334
334
|
snapReader.pipe(output);
|
|
335
335
|
|
|
336
|
-
await null;
|
|
337
336
|
try {
|
|
338
337
|
yield* output;
|
|
339
338
|
} finally {
|
|
340
339
|
gzReader.destroy();
|
|
340
|
+
// eslint-disable-next-line @jessie.js/no-nested-await
|
|
341
341
|
await finished(gzReader);
|
|
342
342
|
const hash = hashStream.digest('hex');
|
|
343
343
|
hash === snapshotID ||
|
package/src/swingStore.js
CHANGED
|
@@ -543,10 +543,6 @@ export function makeSwingStore(dirPath, forceReset, options = {}) {
|
|
|
543
543
|
});
|
|
544
544
|
}
|
|
545
545
|
|
|
546
|
-
function getDatabase() {
|
|
547
|
-
return db;
|
|
548
|
-
}
|
|
549
|
-
|
|
550
546
|
const transcriptStorePublic = {
|
|
551
547
|
initTranscript: transcriptStore.initTranscript,
|
|
552
548
|
rolloverSpan: transcriptStore.rolloverSpan,
|
|
@@ -596,7 +592,6 @@ export function makeSwingStore(dirPath, forceReset, options = {}) {
|
|
|
596
592
|
const debug = {
|
|
597
593
|
serialize,
|
|
598
594
|
dump,
|
|
599
|
-
getDatabase,
|
|
600
595
|
};
|
|
601
596
|
|
|
602
597
|
return harden({
|
package/test/test-bundles.js
CHANGED
package/test/test-deletion.js
CHANGED
package/test/test-export.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
+
import '@endo/init/debug.js';
|
|
3
4
|
import { Buffer } from 'node:buffer';
|
|
4
5
|
|
|
6
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
5
7
|
import test from 'ava';
|
|
8
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
6
9
|
import tmp from 'tmp';
|
|
7
10
|
import bundleSource from '@endo/bundle-source';
|
|
8
11
|
|
|
@@ -52,7 +55,7 @@ async function embundle(filename) {
|
|
|
52
55
|
const bundleFile = new URL(filename, import.meta.url).pathname;
|
|
53
56
|
const bundle = await bundleSource(bundleFile);
|
|
54
57
|
const bundleID = `b1-${bundle.endoZipBase64Sha512}`;
|
|
55
|
-
return
|
|
58
|
+
return [bundleID, bundle];
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
function actLikeAVatRunningACrank(vat, ks, crank, doFail) {
|
|
@@ -119,6 +122,7 @@ test('crank abort leaves no debris in export log', async t => {
|
|
|
119
122
|
crankNum % 3 === 0,
|
|
120
123
|
);
|
|
121
124
|
}
|
|
125
|
+
// eslint-disable-next-line no-await-in-loop
|
|
122
126
|
await ssOut.hostStorage.commit();
|
|
123
127
|
}
|
|
124
128
|
|
|
@@ -214,8 +218,10 @@ async function testExportImport(
|
|
|
214
218
|
actLikeAVatRunningACrank(vat, kernelStorage, crankNum);
|
|
215
219
|
}
|
|
216
220
|
if (block < 3) {
|
|
221
|
+
// eslint-disable-next-line no-await-in-loop
|
|
217
222
|
await fakeAVatSnapshot(vats[block % 2], kernelStorage);
|
|
218
223
|
}
|
|
224
|
+
// eslint-disable-next-line no-await-in-loop
|
|
219
225
|
await ssOut.hostStorage.commit();
|
|
220
226
|
}
|
|
221
227
|
|
package/test/test-hasher.js
CHANGED
package/test/test-import.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
+
import '@endo/init/debug.js';
|
|
4
|
+
|
|
3
5
|
import path from 'path';
|
|
4
6
|
import { createGunzip } from 'zlib';
|
|
5
7
|
import { Readable } from 'stream';
|
|
@@ -12,15 +14,7 @@ import { decodeBase64 } from '@endo/base64';
|
|
|
12
14
|
import { buffer } from '../src/util.js';
|
|
13
15
|
import { importSwingStore, makeSwingStoreExporter } from '../src/index.js';
|
|
14
16
|
|
|
15
|
-
import { tmpDir } from './util.js';
|
|
16
|
-
import {
|
|
17
|
-
buildData,
|
|
18
|
-
bundle0,
|
|
19
|
-
bundle0ID,
|
|
20
|
-
makeExporter,
|
|
21
|
-
snapHash,
|
|
22
|
-
snapshotData,
|
|
23
|
-
} from './exports.js';
|
|
17
|
+
import { tmpDir, makeB0ID } from './util.js';
|
|
24
18
|
|
|
25
19
|
const rank = {
|
|
26
20
|
operational: 1,
|
|
@@ -29,6 +23,15 @@ const rank = {
|
|
|
29
23
|
debug: 4,
|
|
30
24
|
};
|
|
31
25
|
|
|
26
|
+
const snapshotData = 'snapshot data';
|
|
27
|
+
// this snapHash was computed manually
|
|
28
|
+
const snapHash =
|
|
29
|
+
'e7dee7266896538616b630a5da40a90e007726a383e005a9c9c5dd0c2daf9329';
|
|
30
|
+
|
|
31
|
+
/** @type {import('../src/bundleStore.js').Bundle} */
|
|
32
|
+
const bundle0 = { moduleFormat: 'nestedEvaluate', source: '1+1' };
|
|
33
|
+
const bundle0ID = makeB0ID(bundle0);
|
|
34
|
+
|
|
32
35
|
function convert(orig) {
|
|
33
36
|
const bundles = Object.fromEntries(
|
|
34
37
|
Object.entries(orig.bundles).map(([bundleID, encBundle]) => {
|
|
@@ -41,6 +44,38 @@ function convert(orig) {
|
|
|
41
44
|
return { ...orig, bundles };
|
|
42
45
|
}
|
|
43
46
|
|
|
47
|
+
/**
|
|
48
|
+
* @typedef { import('../src/exporter').KVPair } KVPair
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @param { Map<string, string | null> } exportData
|
|
53
|
+
* @param { Map<string, string> } artifacts
|
|
54
|
+
*/
|
|
55
|
+
export function makeExporter(exportData, artifacts) {
|
|
56
|
+
return {
|
|
57
|
+
async *getExportData() {
|
|
58
|
+
for (const [key, value] of exportData.entries()) {
|
|
59
|
+
/** @type { KVPair } */
|
|
60
|
+
const pair = [key, value];
|
|
61
|
+
yield pair;
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
async *getArtifactNames() {
|
|
65
|
+
for (const name of artifacts.keys()) {
|
|
66
|
+
yield name;
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
async *getArtifact(name) {
|
|
70
|
+
const data = artifacts.get(name);
|
|
71
|
+
assert(data, `missing artifact ${name}`);
|
|
72
|
+
yield Buffer.from(data);
|
|
73
|
+
},
|
|
74
|
+
// eslint-disable-next-line no-empty-function
|
|
75
|
+
async close() {},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
44
79
|
test('import empty', async t => {
|
|
45
80
|
const [dbDir, cleanup] = await tmpDir('testdb');
|
|
46
81
|
t.teardown(cleanup);
|
|
@@ -57,6 +92,66 @@ test('import empty', async t => {
|
|
|
57
92
|
});
|
|
58
93
|
});
|
|
59
94
|
|
|
95
|
+
export function buildData() {
|
|
96
|
+
// build an export manually
|
|
97
|
+
const exportData = new Map();
|
|
98
|
+
const artifacts = new Map();
|
|
99
|
+
|
|
100
|
+
// shadow kvStore
|
|
101
|
+
exportData.set('kv.key1', 'value1');
|
|
102
|
+
|
|
103
|
+
// now add artifacts and metadata in pairs
|
|
104
|
+
|
|
105
|
+
artifacts.set(`bundle.${bundle0ID}`, JSON.stringify(bundle0));
|
|
106
|
+
exportData.set(`bundle.${bundle0ID}`, bundle0ID);
|
|
107
|
+
|
|
108
|
+
const sbase = { vatID: 'v1', hash: snapHash, inUse: 0 };
|
|
109
|
+
const tbase = { vatID: 'v1', startPos: 0, isCurrent: 0, incarnation: 1 };
|
|
110
|
+
const addTS = (key, obj) =>
|
|
111
|
+
exportData.set(key, JSON.stringify({ ...tbase, ...obj }));
|
|
112
|
+
const t0hash =
|
|
113
|
+
'5bee0f44eca02f23eab03703e84ed2647d5d117fed99e1c30a3b424b7f082ab9';
|
|
114
|
+
const t2hash =
|
|
115
|
+
'57152efdd7fdf75c03371d2b4f1088d5bf3eae7fe643babce527ff81df38998c';
|
|
116
|
+
const t5hash =
|
|
117
|
+
'1947001e78e01bd1e773feb22b4ffc530447373b9de9274d5d5fbda3f23dbf2b';
|
|
118
|
+
const t8hash =
|
|
119
|
+
'e6b42c6a3fb94285a93162f25a9fc0145fd4c5bb144917dc572c50ae2d02ee69';
|
|
120
|
+
|
|
121
|
+
addTS(`transcript.v1.0`, { incarnation: 0, endPos: 2, hash: t0hash });
|
|
122
|
+
artifacts.set(`transcript.v1.0.2`, 'start-worker\nshutdown-worker\n');
|
|
123
|
+
|
|
124
|
+
addTS(`transcript.v1.2`, { startPos: 2, endPos: 5, hash: t2hash });
|
|
125
|
+
artifacts.set(
|
|
126
|
+
`transcript.v1.2.5`,
|
|
127
|
+
'start-worker\ndelivery1\nsave-snapshot\n',
|
|
128
|
+
);
|
|
129
|
+
exportData.set(`snapshot.v1.4`, JSON.stringify({ ...sbase, snapPos: 4 }));
|
|
130
|
+
artifacts.set(`snapshot.v1.4`, snapshotData);
|
|
131
|
+
|
|
132
|
+
addTS(`transcript.v1.5`, { startPos: 5, endPos: 8, hash: t5hash });
|
|
133
|
+
artifacts.set(
|
|
134
|
+
'transcript.v1.5.8',
|
|
135
|
+
'load-snapshot\ndelivery2\nsave-snapshot\n',
|
|
136
|
+
);
|
|
137
|
+
exportData.set(
|
|
138
|
+
`snapshot.v1.7`,
|
|
139
|
+
JSON.stringify({ ...sbase, snapPos: 7, inUse: 1 }),
|
|
140
|
+
);
|
|
141
|
+
artifacts.set(`snapshot.v1.7`, snapshotData);
|
|
142
|
+
|
|
143
|
+
artifacts.set('transcript.v1.8.10', 'load-snapshot\ndelivery3\n');
|
|
144
|
+
exportData.set(`snapshot.v1.current`, 'snapshot.v1.7');
|
|
145
|
+
addTS(`transcript.v1.current`, {
|
|
146
|
+
startPos: 8,
|
|
147
|
+
endPos: 10,
|
|
148
|
+
isCurrent: 1,
|
|
149
|
+
hash: t8hash,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
return { exportData, artifacts, t0hash, t2hash, t5hash, t8hash };
|
|
153
|
+
}
|
|
154
|
+
|
|
60
155
|
const importTest = test.macro(async (t, mode) => {
|
|
61
156
|
/** @typedef {import('../src/internal.js').ArtifactMode} ArtifactMode */
|
|
62
157
|
const artifactMode = /** @type {ArtifactMode} */ (mode);
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
+
import '@endo/init/debug.js';
|
|
4
|
+
|
|
3
5
|
import path from 'path';
|
|
4
6
|
import test from 'ava';
|
|
5
7
|
import sqlite3 from 'better-sqlite3';
|
|
6
8
|
|
|
7
9
|
import { importSwingStore, openSwingStore } from '../src/index.js';
|
|
8
10
|
|
|
9
|
-
import { makeExporter, buildData } from './
|
|
11
|
+
import { makeExporter, buildData } from './test-import.js';
|
|
10
12
|
import { tmpDir } from './util.js';
|
|
11
13
|
|
|
12
14
|
test('repair metadata', async t => {
|
package/test/test-snapstore.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
+
import '@endo/init/debug.js';
|
|
3
4
|
import { Buffer } from 'node:buffer';
|
|
4
5
|
import zlib from 'zlib';
|
|
5
6
|
import sqlite3 from 'better-sqlite3';
|
|
6
7
|
|
|
8
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
7
9
|
import test from 'ava';
|
|
10
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
8
11
|
import { makeMeasureSeconds } from '@agoric/internal';
|
|
9
12
|
import { makeSnapStore } from '../src/snapStore.js';
|
|
10
13
|
|
|
@@ -100,6 +103,7 @@ test('snapStore prepare / commit delete is robust', async t => {
|
|
|
100
103
|
|
|
101
104
|
const hashes = [];
|
|
102
105
|
for (let i = 0; i < 5; i += 1) {
|
|
106
|
+
// eslint-disable-next-line no-await-in-loop
|
|
103
107
|
const { hash } = await store.saveSnapshot(
|
|
104
108
|
'fakeVatID2',
|
|
105
109
|
i,
|
|
@@ -129,6 +133,7 @@ test('snapStore prepare / commit delete is robust', async t => {
|
|
|
129
133
|
t.is(sqlCountSnapshots.get(), 0);
|
|
130
134
|
|
|
131
135
|
for (let i = 0; i < 5; i += 1) {
|
|
136
|
+
// eslint-disable-next-line no-await-in-loop
|
|
132
137
|
const { hash } = await store.saveSnapshot(
|
|
133
138
|
'fakeVatID4',
|
|
134
139
|
i,
|
package/test/test-state.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
+
import '@endo/init/debug.js';
|
|
4
|
+
|
|
3
5
|
import tmp from 'tmp';
|
|
4
6
|
import test from 'ava';
|
|
5
7
|
|
|
@@ -30,7 +32,7 @@ async function embundle(filename) {
|
|
|
30
32
|
const bundleFile = new URL(filename, import.meta.url).pathname;
|
|
31
33
|
const bundle = await bundleSource(bundleFile);
|
|
32
34
|
const bundleID = `b1-${bundle.endoZipBase64Sha512}`;
|
|
33
|
-
return
|
|
35
|
+
return [bundleID, bundle];
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
function* iterate(kvStore, start, end) {
|
package/test/exports.js
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { Buffer } from 'buffer';
|
|
2
|
-
import { makeB0ID } from './util.js';
|
|
3
|
-
|
|
4
|
-
export const snapshotData = 'snapshot data';
|
|
5
|
-
// this snapHash was computed manually
|
|
6
|
-
export const snapHash =
|
|
7
|
-
'e7dee7266896538616b630a5da40a90e007726a383e005a9c9c5dd0c2daf9329';
|
|
8
|
-
|
|
9
|
-
/** @type {import('../src/bundleStore.js').Bundle} */
|
|
10
|
-
export const bundle0 = { moduleFormat: 'nestedEvaluate', source: '1+1' };
|
|
11
|
-
export const bundle0ID = makeB0ID(bundle0);
|
|
12
|
-
|
|
13
|
-
export function buildData() {
|
|
14
|
-
// build an export manually
|
|
15
|
-
const exportData = new Map();
|
|
16
|
-
const artifacts = new Map();
|
|
17
|
-
|
|
18
|
-
// shadow kvStore
|
|
19
|
-
exportData.set('kv.key1', 'value1');
|
|
20
|
-
|
|
21
|
-
// now add artifacts and metadata in pairs
|
|
22
|
-
|
|
23
|
-
artifacts.set(`bundle.${bundle0ID}`, JSON.stringify(bundle0));
|
|
24
|
-
exportData.set(`bundle.${bundle0ID}`, bundle0ID);
|
|
25
|
-
|
|
26
|
-
const sbase = { vatID: 'v1', hash: snapHash, inUse: 0 };
|
|
27
|
-
const tbase = { vatID: 'v1', startPos: 0, isCurrent: 0, incarnation: 1 };
|
|
28
|
-
const addTS = (key, obj) =>
|
|
29
|
-
exportData.set(key, JSON.stringify({ ...tbase, ...obj }));
|
|
30
|
-
const t0hash =
|
|
31
|
-
'5bee0f44eca02f23eab03703e84ed2647d5d117fed99e1c30a3b424b7f082ab9';
|
|
32
|
-
const t2hash =
|
|
33
|
-
'57152efdd7fdf75c03371d2b4f1088d5bf3eae7fe643babce527ff81df38998c';
|
|
34
|
-
const t5hash =
|
|
35
|
-
'1947001e78e01bd1e773feb22b4ffc530447373b9de9274d5d5fbda3f23dbf2b';
|
|
36
|
-
const t8hash =
|
|
37
|
-
'e6b42c6a3fb94285a93162f25a9fc0145fd4c5bb144917dc572c50ae2d02ee69';
|
|
38
|
-
|
|
39
|
-
addTS(`transcript.v1.0`, { incarnation: 0, endPos: 2, hash: t0hash });
|
|
40
|
-
artifacts.set(`transcript.v1.0.2`, 'start-worker\nshutdown-worker\n');
|
|
41
|
-
|
|
42
|
-
addTS(`transcript.v1.2`, { startPos: 2, endPos: 5, hash: t2hash });
|
|
43
|
-
artifacts.set(
|
|
44
|
-
`transcript.v1.2.5`,
|
|
45
|
-
'start-worker\ndelivery1\nsave-snapshot\n',
|
|
46
|
-
);
|
|
47
|
-
exportData.set(`snapshot.v1.4`, JSON.stringify({ ...sbase, snapPos: 4 }));
|
|
48
|
-
artifacts.set(`snapshot.v1.4`, snapshotData);
|
|
49
|
-
|
|
50
|
-
addTS(`transcript.v1.5`, { startPos: 5, endPos: 8, hash: t5hash });
|
|
51
|
-
artifacts.set(
|
|
52
|
-
'transcript.v1.5.8',
|
|
53
|
-
'load-snapshot\ndelivery2\nsave-snapshot\n',
|
|
54
|
-
);
|
|
55
|
-
exportData.set(
|
|
56
|
-
`snapshot.v1.7`,
|
|
57
|
-
JSON.stringify({ ...sbase, snapPos: 7, inUse: 1 }),
|
|
58
|
-
);
|
|
59
|
-
artifacts.set(`snapshot.v1.7`, snapshotData);
|
|
60
|
-
|
|
61
|
-
artifacts.set('transcript.v1.8.10', 'load-snapshot\ndelivery3\n');
|
|
62
|
-
exportData.set(`snapshot.v1.current`, 'snapshot.v1.7');
|
|
63
|
-
addTS(`transcript.v1.current`, {
|
|
64
|
-
startPos: 8,
|
|
65
|
-
endPos: 10,
|
|
66
|
-
isCurrent: 1,
|
|
67
|
-
hash: t8hash,
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
return { exportData, artifacts, t0hash, t2hash, t5hash, t8hash };
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* @param { Map<string, string | null> } exportData
|
|
75
|
-
* @param { Map<string, string> } artifacts
|
|
76
|
-
*/
|
|
77
|
-
export function makeExporter(exportData, artifacts) {
|
|
78
|
-
return {
|
|
79
|
-
async *getExportData() {
|
|
80
|
-
for (const [key, value] of exportData.entries()) {
|
|
81
|
-
/** @type { import('../src/exporter.js').KVPair } */
|
|
82
|
-
const pair = [key, value];
|
|
83
|
-
yield pair;
|
|
84
|
-
}
|
|
85
|
-
},
|
|
86
|
-
async *getArtifactNames() {
|
|
87
|
-
for (const name of artifacts.keys()) {
|
|
88
|
-
yield name;
|
|
89
|
-
}
|
|
90
|
-
},
|
|
91
|
-
async *getArtifact(name) {
|
|
92
|
-
const data = artifacts.get(name);
|
|
93
|
-
assert(data, `missing artifact ${name}`);
|
|
94
|
-
yield Buffer.from(data);
|
|
95
|
-
},
|
|
96
|
-
// eslint-disable-next-line no-empty-function
|
|
97
|
-
async close() {},
|
|
98
|
-
};
|
|
99
|
-
}
|