@agoric/cosmic-swingset 0.41.4-dev-7bfadd3.0 → 0.41.4-dev-f2445bc.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/package.json +11 -11
- package/src/export-kernel-db.js +103 -48
- package/src/import-kernel-db.js +126 -37
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/cosmic-swingset",
|
|
3
|
-
"version": "0.41.4-dev-
|
|
3
|
+
"version": "0.41.4-dev-f2445bc.0+f2445bc",
|
|
4
4
|
"description": "Agoric's Cosmos blockchain integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,15 +22,15 @@
|
|
|
22
22
|
"author": "Agoric",
|
|
23
23
|
"license": "Apache-2.0",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@agoric/assert": "0.6.1-dev-
|
|
26
|
-
"@agoric/cosmos": "0.34.2-dev-
|
|
27
|
-
"@agoric/deploy-script-support": "0.10.4-dev-
|
|
28
|
-
"@agoric/internal": "0.3.3-dev-
|
|
29
|
-
"@agoric/store": "0.9.3-dev-
|
|
30
|
-
"@agoric/swing-store": "0.9.2-dev-
|
|
31
|
-
"@agoric/swingset-vat": "0.32.3-dev-
|
|
32
|
-
"@agoric/telemetry": "0.6.3-dev-
|
|
33
|
-
"@agoric/vm-config": "0.1.1-dev-
|
|
25
|
+
"@agoric/assert": "0.6.1-dev-f2445bc.0+f2445bc",
|
|
26
|
+
"@agoric/cosmos": "0.34.2-dev-f2445bc.0+f2445bc",
|
|
27
|
+
"@agoric/deploy-script-support": "0.10.4-dev-f2445bc.0+f2445bc",
|
|
28
|
+
"@agoric/internal": "0.3.3-dev-f2445bc.0+f2445bc",
|
|
29
|
+
"@agoric/store": "0.9.3-dev-f2445bc.0+f2445bc",
|
|
30
|
+
"@agoric/swing-store": "0.9.2-dev-f2445bc.0+f2445bc",
|
|
31
|
+
"@agoric/swingset-vat": "0.32.3-dev-f2445bc.0+f2445bc",
|
|
32
|
+
"@agoric/telemetry": "0.6.3-dev-f2445bc.0+f2445bc",
|
|
33
|
+
"@agoric/vm-config": "0.1.1-dev-f2445bc.0+f2445bc",
|
|
34
34
|
"@endo/bundle-source": "^2.5.2",
|
|
35
35
|
"@endo/far": "^0.2.19",
|
|
36
36
|
"@endo/import-bundle": "^0.3.5",
|
|
@@ -65,5 +65,5 @@
|
|
|
65
65
|
],
|
|
66
66
|
"timeout": "20m"
|
|
67
67
|
},
|
|
68
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "f2445bcb471c26169ea8052d04e96d51ef9f1487"
|
|
69
69
|
}
|
package/src/export-kernel-db.js
CHANGED
|
@@ -11,7 +11,7 @@ import pathPower from 'path';
|
|
|
11
11
|
import { fileURLToPath } from 'url';
|
|
12
12
|
|
|
13
13
|
import { makePromiseKit } from '@endo/promise-kit';
|
|
14
|
-
import { Fail } from '@agoric/assert';
|
|
14
|
+
import { Fail, q } from '@agoric/assert';
|
|
15
15
|
import { makeAggregateError } from '@agoric/internal';
|
|
16
16
|
import { makeShutdown } from '@agoric/internal/src/node/shutdown.js';
|
|
17
17
|
import { openSwingStore, makeSwingStoreExporter } from '@agoric/swing-store';
|
|
@@ -19,26 +19,66 @@ import { openSwingStore, makeSwingStoreExporter } from '@agoric/swing-store';
|
|
|
19
19
|
import { isEntrypoint } from './helpers/is-entrypoint.js';
|
|
20
20
|
import { makeProcessValue } from './helpers/process-value.js';
|
|
21
21
|
|
|
22
|
-
/** @typedef {'current' | 'archival' | 'debug'} SwingStoreExportMode */
|
|
23
|
-
|
|
24
22
|
// ExportManifestFilename is the manifest filename which must be synchronized
|
|
25
23
|
// with the golang SwingStoreExportsHandler in golang/cosmos/x/swingset/keeper/swing_store_exports_handler.go
|
|
26
24
|
export const ExportManifestFileName = 'export-manifest.json';
|
|
27
25
|
|
|
28
|
-
// eslint-disable-next-line jsdoc/require-returns-check
|
|
29
26
|
/**
|
|
30
|
-
* @
|
|
31
|
-
* @
|
|
27
|
+
* @typedef {'none' // No artifacts included
|
|
28
|
+
* | import("@agoric/swing-store").ArtifactMode
|
|
29
|
+
* } SwingStoreArtifactMode
|
|
32
30
|
*/
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @typedef {'skip' // Do not include any "export data" (artifacts only)
|
|
34
|
+
* | 'repair-metadata' // Add missing artifact metadata (import only)
|
|
35
|
+
* | 'all' // Include all export data, create new swing-store on import
|
|
36
|
+
* } SwingStoreExportDataMode
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @param {SwingStoreArtifactMode | undefined} artifactMode
|
|
41
|
+
* @returns {import("@agoric/swing-store").ArtifactMode}
|
|
42
|
+
*/
|
|
43
|
+
export const getEffectiveArtifactMode = artifactMode => {
|
|
44
|
+
switch (artifactMode) {
|
|
45
|
+
case 'none':
|
|
46
|
+
case 'operational':
|
|
47
|
+
return 'operational';
|
|
48
|
+
case undefined:
|
|
49
|
+
case 'replay':
|
|
50
|
+
return 'replay';
|
|
36
51
|
case 'archival':
|
|
37
52
|
case 'debug':
|
|
53
|
+
return artifactMode;
|
|
54
|
+
default:
|
|
55
|
+
throw Fail`Invalid value ${q(artifactMode)} for "artifact-mode"`;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/** @type {(artifactMode: string | undefined) => asserts artifactMode is SwingStoreArtifactMode | undefined} */
|
|
60
|
+
export const checkArtifactMode = getEffectiveArtifactMode;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @param {string | undefined} mode
|
|
64
|
+
* @param {boolean} [isImport]
|
|
65
|
+
* @returns {asserts mode is SwingStoreExportDataMode | undefined}
|
|
66
|
+
*/
|
|
67
|
+
export const checkExportDataMode = (mode, isImport = false) => {
|
|
68
|
+
switch (mode) {
|
|
69
|
+
case 'skip':
|
|
38
70
|
case undefined:
|
|
39
71
|
break;
|
|
72
|
+
case 'all':
|
|
73
|
+
break;
|
|
74
|
+
case 'repair-metadata': {
|
|
75
|
+
if (isImport) {
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
// Fall through
|
|
79
|
+
}
|
|
40
80
|
default:
|
|
41
|
-
throw Fail`Invalid value ${mode} for "export-mode"`;
|
|
81
|
+
throw Fail`Invalid value ${q(mode)} for "export-data-mode"`;
|
|
42
82
|
}
|
|
43
83
|
};
|
|
44
84
|
|
|
@@ -54,7 +94,7 @@ const checkExportMode = mode => {
|
|
|
54
94
|
*
|
|
55
95
|
* @typedef {object} StateSyncManifest
|
|
56
96
|
* @property {number} blockHeight the block height corresponding to this export
|
|
57
|
-
* @property {
|
|
97
|
+
* @property {SwingStoreArtifactMode} [artifactMode]
|
|
58
98
|
* @property {string} [data] file name containing the swingStore "export data"
|
|
59
99
|
* @property {Array<[artifactName: string, fileName: string]>} artifacts
|
|
60
100
|
* List of swingStore export artifacts which can be validated by the export data
|
|
@@ -73,8 +113,8 @@ const checkExportMode = mode => {
|
|
|
73
113
|
* @property {string} stateDir the directory containing the SwingStore to export
|
|
74
114
|
* @property {string} exportDir the directory in which to place the exported artifacts and manifest
|
|
75
115
|
* @property {number} [blockHeight] block height to check for
|
|
76
|
-
* @property {
|
|
77
|
-
* @property {
|
|
116
|
+
* @property {SwingStoreArtifactMode} [artifactMode] the level of artifacts to include in the export
|
|
117
|
+
* @property {SwingStoreExportDataMode} [exportDataMode] include a synthetic artifact for the export data in the export
|
|
78
118
|
*/
|
|
79
119
|
|
|
80
120
|
/**
|
|
@@ -90,10 +130,12 @@ export const validateExporterOptions = options => {
|
|
|
90
130
|
options.blockHeight == null ||
|
|
91
131
|
typeof options.blockHeight === 'number' ||
|
|
92
132
|
Fail`optional blockHeight option not a number`;
|
|
93
|
-
|
|
94
|
-
options.
|
|
95
|
-
|
|
96
|
-
|
|
133
|
+
checkArtifactMode(options.artifactMode);
|
|
134
|
+
checkExportDataMode(options.exportDataMode);
|
|
135
|
+
|
|
136
|
+
options.includeExportData === undefined ||
|
|
137
|
+
Fail`deprecated includeExportData option found`;
|
|
138
|
+
options.exportMode === undefined || Fail`deprecated exportMode option found`;
|
|
97
139
|
};
|
|
98
140
|
|
|
99
141
|
/**
|
|
@@ -107,7 +149,7 @@ export const validateExporterOptions = options => {
|
|
|
107
149
|
* @returns {StateSyncExporter}
|
|
108
150
|
*/
|
|
109
151
|
export const initiateSwingStoreExport = (
|
|
110
|
-
{ stateDir, exportDir, blockHeight,
|
|
152
|
+
{ stateDir, exportDir, blockHeight, artifactMode, exportDataMode },
|
|
111
153
|
{
|
|
112
154
|
fs: { open, writeFile },
|
|
113
155
|
pathResolve,
|
|
@@ -116,11 +158,7 @@ export const initiateSwingStoreExport = (
|
|
|
116
158
|
log = console.log,
|
|
117
159
|
},
|
|
118
160
|
) => {
|
|
119
|
-
const
|
|
120
|
-
if (effectiveExportMode !== 'current' && !includeExportData) {
|
|
121
|
-
throw Fail`Must include export data if export mode not "current"`;
|
|
122
|
-
}
|
|
123
|
-
|
|
161
|
+
const effectiveArtifactMode = getEffectiveArtifactMode(artifactMode);
|
|
124
162
|
/** @type {number | undefined} */
|
|
125
163
|
let savedBlockHeight;
|
|
126
164
|
|
|
@@ -140,7 +178,9 @@ export const initiateSwingStoreExport = (
|
|
|
140
178
|
const manifestFile = await open(manifestPath, 'wx');
|
|
141
179
|
cleanup.push(async () => manifestFile.close());
|
|
142
180
|
|
|
143
|
-
const swingStoreExporter = makeExporter(stateDir,
|
|
181
|
+
const swingStoreExporter = makeExporter(stateDir, {
|
|
182
|
+
artifactMode: effectiveArtifactMode,
|
|
183
|
+
});
|
|
144
184
|
cleanup.push(async () => swingStoreExporter.close());
|
|
145
185
|
|
|
146
186
|
const { hostStorage } = openDB(stateDir);
|
|
@@ -150,7 +190,9 @@ export const initiateSwingStoreExport = (
|
|
|
150
190
|
|
|
151
191
|
if (blockHeight) {
|
|
152
192
|
blockHeight === savedBlockHeight ||
|
|
153
|
-
Fail`DB at unexpected block height ${savedBlockHeight} (expected ${
|
|
193
|
+
Fail`DB at unexpected block height ${q(savedBlockHeight)} (expected ${q(
|
|
194
|
+
blockHeight,
|
|
195
|
+
)})`;
|
|
154
196
|
}
|
|
155
197
|
|
|
156
198
|
abortIfStopped();
|
|
@@ -160,11 +202,11 @@ export const initiateSwingStoreExport = (
|
|
|
160
202
|
/** @type {StateSyncManifest} */
|
|
161
203
|
const manifest = {
|
|
162
204
|
blockHeight: savedBlockHeight,
|
|
163
|
-
|
|
205
|
+
artifactMode: artifactMode || effectiveArtifactMode,
|
|
164
206
|
artifacts: [],
|
|
165
207
|
};
|
|
166
208
|
|
|
167
|
-
if (
|
|
209
|
+
if (exportDataMode === 'all') {
|
|
168
210
|
log?.(`Writing Export Data`);
|
|
169
211
|
const fileName = `export-data.jsonl`;
|
|
170
212
|
const exportDataFile = await open(pathResolve(exportDir, fileName), 'wx');
|
|
@@ -178,14 +220,16 @@ export const initiateSwingStoreExport = (
|
|
|
178
220
|
}
|
|
179
221
|
abortIfStopped();
|
|
180
222
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
223
|
+
if (artifactMode !== 'none') {
|
|
224
|
+
for await (const artifactName of swingStoreExporter.getArtifactNames()) {
|
|
225
|
+
abortIfStopped();
|
|
226
|
+
log?.(`Writing artifact: ${artifactName}`);
|
|
227
|
+
const artifactData = swingStoreExporter.getArtifact(artifactName);
|
|
228
|
+
// Use artifactName as the file name as we trust swingStore to generate
|
|
229
|
+
// artifact names that are valid file names.
|
|
230
|
+
await writeFile(pathResolve(exportDir, artifactName), artifactData);
|
|
231
|
+
manifest.artifacts.push([artifactName, artifactName]);
|
|
232
|
+
}
|
|
189
233
|
}
|
|
190
234
|
|
|
191
235
|
await manifestFile.write(JSON.stringify(manifest, null, 2));
|
|
@@ -269,11 +313,22 @@ export const main = async (
|
|
|
269
313
|
/** @type {string} */ (processValue.getFlag('export-dir', '.')),
|
|
270
314
|
);
|
|
271
315
|
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
316
|
+
const artifactMode = /** @type {SwingStoreArtifactMode | undefined} */ (
|
|
317
|
+
processValue.getFlag('artifact-mode')
|
|
318
|
+
);
|
|
319
|
+
checkArtifactMode(artifactMode);
|
|
320
|
+
|
|
321
|
+
const exportDataMode = processValue.getFlag('export-data-mode');
|
|
322
|
+
checkExportDataMode(exportDataMode);
|
|
323
|
+
|
|
324
|
+
if (
|
|
325
|
+
processValue.getBoolean({ flagName: 'include-export-data' }) !== undefined
|
|
326
|
+
) {
|
|
327
|
+
throw Fail`deprecated "include-export-data" options, use "export-data-mode" instead`;
|
|
328
|
+
}
|
|
329
|
+
if (processValue.getFlag('export-mode') !== undefined) {
|
|
330
|
+
throw Fail`deprecated "export-mode" options, use "artifact-mode" instead`;
|
|
331
|
+
}
|
|
277
332
|
|
|
278
333
|
const checkBlockHeight = processValue.getInteger({
|
|
279
334
|
flagName: 'check-block-height',
|
|
@@ -290,8 +345,8 @@ export const main = async (
|
|
|
290
345
|
stateDir,
|
|
291
346
|
exportDir,
|
|
292
347
|
blockHeight: checkBlockHeight,
|
|
293
|
-
|
|
294
|
-
|
|
348
|
+
artifactMode,
|
|
349
|
+
exportDataMode,
|
|
295
350
|
},
|
|
296
351
|
{
|
|
297
352
|
fs,
|
|
@@ -332,7 +387,7 @@ export const main = async (
|
|
|
332
387
|
* @returns {StateSyncExporter}
|
|
333
388
|
*/
|
|
334
389
|
export const spawnSwingStoreExport = (
|
|
335
|
-
{ stateDir, exportDir, blockHeight,
|
|
390
|
+
{ stateDir, exportDir, blockHeight, artifactMode, exportDataMode },
|
|
336
391
|
{ fork, verbose },
|
|
337
392
|
) => {
|
|
338
393
|
const args = ['--state-dir', stateDir, '--export-dir', exportDir];
|
|
@@ -341,12 +396,12 @@ export const spawnSwingStoreExport = (
|
|
|
341
396
|
args.push('--check-block-height', String(blockHeight));
|
|
342
397
|
}
|
|
343
398
|
|
|
344
|
-
if (
|
|
345
|
-
args.push('--
|
|
399
|
+
if (artifactMode) {
|
|
400
|
+
args.push('--artifact-mode', artifactMode);
|
|
346
401
|
}
|
|
347
402
|
|
|
348
|
-
if (
|
|
349
|
-
args.push('--
|
|
403
|
+
if (exportDataMode) {
|
|
404
|
+
args.push('--export-data-mode', exportDataMode);
|
|
350
405
|
}
|
|
351
406
|
|
|
352
407
|
if (verbose) {
|
|
@@ -398,7 +453,7 @@ export const spawnSwingStoreExport = (
|
|
|
398
453
|
}
|
|
399
454
|
default: {
|
|
400
455
|
// @ts-expect-error exhaustive check
|
|
401
|
-
Fail`Unexpected ${msg.type} message`;
|
|
456
|
+
Fail`Unexpected ${q(msg.type)} message`;
|
|
402
457
|
}
|
|
403
458
|
}
|
|
404
459
|
};
|
package/src/import-kernel-db.js
CHANGED
|
@@ -12,19 +12,24 @@ import fsPromisesPower from 'fs/promises';
|
|
|
12
12
|
import pathPower from 'path';
|
|
13
13
|
|
|
14
14
|
import BufferLineTransform from '@agoric/internal/src/node/buffer-line-transform.js';
|
|
15
|
-
import { Fail } from '@agoric/assert';
|
|
16
|
-
import { importSwingStore } from '@agoric/swing-store';
|
|
15
|
+
import { Fail, q } from '@agoric/assert';
|
|
16
|
+
import { importSwingStore, openSwingStore } from '@agoric/swing-store';
|
|
17
17
|
|
|
18
18
|
import { isEntrypoint } from './helpers/is-entrypoint.js';
|
|
19
19
|
import { makeProcessValue } from './helpers/process-value.js';
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
ExportManifestFileName,
|
|
22
|
+
checkExportDataMode,
|
|
23
|
+
checkArtifactMode,
|
|
24
|
+
} from './export-kernel-db.js';
|
|
21
25
|
|
|
22
26
|
/**
|
|
23
27
|
* @typedef {object} StateSyncImporterOptions
|
|
24
28
|
* @property {string} stateDir the directory containing the SwingStore to export
|
|
25
29
|
* @property {string} exportDir the directory where to place the exported artifacts and manifest
|
|
26
30
|
* @property {number} [blockHeight] block height to check for
|
|
27
|
-
* @property {
|
|
31
|
+
* @property {import('./export-kernel-db.js').SwingStoreExportDataMode} [exportDataMode] how to handle export data
|
|
32
|
+
* @property {import('./export-kernel-db.js').SwingStoreArtifactMode} [artifactMode] the level of historical artifacts to import
|
|
28
33
|
*/
|
|
29
34
|
|
|
30
35
|
/**
|
|
@@ -40,9 +45,57 @@ export const validateImporterOptions = options => {
|
|
|
40
45
|
options.blockHeight == null ||
|
|
41
46
|
typeof options.blockHeight === 'number' ||
|
|
42
47
|
Fail`optional blockHeight option not a number`;
|
|
43
|
-
options.
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
checkExportDataMode(options.exportDataMode, true);
|
|
49
|
+
checkArtifactMode(options.artifactMode);
|
|
50
|
+
options.includeHistorical === undefined ||
|
|
51
|
+
Fail`deprecated includeHistorical option found`;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @param {Pick<StateSyncImporterOptions, 'artifactMode' | 'exportDataMode' >} options
|
|
56
|
+
* @param {Readonly<import('./export-kernel-db.js').StateSyncManifest>} manifest
|
|
57
|
+
* @returns {import('@agoric/swing-store').ImportSwingStoreOptions}
|
|
58
|
+
*/
|
|
59
|
+
const checkAndGetImportSwingStoreOptions = (options, manifest) => {
|
|
60
|
+
typeof manifest.blockHeight === 'number' ||
|
|
61
|
+
Fail`Cannot restore snapshot without block height`;
|
|
62
|
+
|
|
63
|
+
manifest.data || Fail`State-sync manifest missing export data`;
|
|
64
|
+
|
|
65
|
+
const { artifactMode = manifest.artifactMode || 'replay' } = options;
|
|
66
|
+
|
|
67
|
+
if (artifactMode === 'none') {
|
|
68
|
+
throw Fail`Cannot import "export data" without at least "operational" artifacts`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
manifest.artifacts?.length ||
|
|
72
|
+
Fail`State-sync manifest missing required artifacts`;
|
|
73
|
+
|
|
74
|
+
switch (artifactMode) {
|
|
75
|
+
case 'debug':
|
|
76
|
+
// eslint-disable-next-line no-fallthrough
|
|
77
|
+
case 'operational':
|
|
78
|
+
if (manifest.artifactMode === 'operational') break;
|
|
79
|
+
// eslint-disable-next-line no-fallthrough
|
|
80
|
+
case 'replay':
|
|
81
|
+
if (manifest.artifactMode === 'replay') break;
|
|
82
|
+
// eslint-disable-next-line no-fallthrough
|
|
83
|
+
case 'archival':
|
|
84
|
+
if (manifest.artifactMode === 'archival') break;
|
|
85
|
+
if (
|
|
86
|
+
manifest.artifactMode === undefined ||
|
|
87
|
+
manifest.artifactMode === 'debug'
|
|
88
|
+
) {
|
|
89
|
+
// assume the export has sufficient data
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
throw Fail`State-sync manifest has insufficient artifacts: requested import artifact mode: ${q(
|
|
93
|
+
artifactMode,
|
|
94
|
+
)}, manifest has ${q(manifest.artifactMode)} artifacts`;
|
|
95
|
+
default:
|
|
96
|
+
throw Fail`Unexpected artifactMode ${q(artifactMode)}`;
|
|
97
|
+
}
|
|
98
|
+
return { artifactMode };
|
|
46
99
|
};
|
|
47
100
|
|
|
48
101
|
/**
|
|
@@ -51,15 +104,17 @@ export const validateImporterOptions = options => {
|
|
|
51
104
|
* @param {Pick<import('fs/promises'), 'readFile'> & Pick<import('fs'), 'createReadStream'>} powers.fs
|
|
52
105
|
* @param {import('path')['resolve']} powers.pathResolve
|
|
53
106
|
* @param {typeof import('@agoric/swing-store')['importSwingStore']} [powers.importSwingStore]
|
|
107
|
+
* @param {typeof import('@agoric/swing-store')['openSwingStore']} [powers.openSwingStore]
|
|
54
108
|
* @param {null | ((...args: any[]) => void)} [powers.log]
|
|
55
109
|
* @returns {Promise<void>}
|
|
56
110
|
*/
|
|
57
111
|
export const performStateSyncImport = async (
|
|
58
|
-
{ stateDir, exportDir, blockHeight,
|
|
112
|
+
{ stateDir, exportDir, blockHeight, exportDataMode = 'all', artifactMode },
|
|
59
113
|
{
|
|
60
114
|
fs: { createReadStream, readFile },
|
|
61
115
|
pathResolve,
|
|
62
116
|
importSwingStore: importDB = importSwingStore,
|
|
117
|
+
openSwingStore: openDB = openSwingStore,
|
|
63
118
|
log = console.log,
|
|
64
119
|
},
|
|
65
120
|
) => {
|
|
@@ -67,7 +122,9 @@ export const performStateSyncImport = async (
|
|
|
67
122
|
const safeExportFileResolve = allegedRelativeFilename => {
|
|
68
123
|
const resolvedPath = pathResolve(exportDir, allegedRelativeFilename);
|
|
69
124
|
resolvedPath.startsWith(exportDir) ||
|
|
70
|
-
Fail`Exported file ${
|
|
125
|
+
Fail`Exported file ${q(
|
|
126
|
+
allegedRelativeFilename,
|
|
127
|
+
)} must be in export dir ${q(exportDir)}`;
|
|
71
128
|
return resolvedPath;
|
|
72
129
|
};
|
|
73
130
|
|
|
@@ -78,26 +135,12 @@ export const performStateSyncImport = async (
|
|
|
78
135
|
);
|
|
79
136
|
|
|
80
137
|
if (blockHeight !== undefined && manifest.blockHeight !== blockHeight) {
|
|
81
|
-
Fail`State-sync manifest for unexpected block height ${
|
|
138
|
+
Fail`State-sync manifest for unexpected block height ${q(
|
|
139
|
+
manifest.blockHeight,
|
|
140
|
+
)} (expected ${q(blockHeight)})`;
|
|
82
141
|
}
|
|
83
142
|
|
|
84
|
-
|
|
85
|
-
throw Fail`State-sync manifest missing export data`;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (!manifest.artifacts) {
|
|
89
|
-
throw Fail`State-sync manifest missing required artifacts`;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const artifacts = harden(Object.fromEntries(manifest.artifacts));
|
|
93
|
-
|
|
94
|
-
if (
|
|
95
|
-
includeHistorical &&
|
|
96
|
-
manifest.mode !== 'archival' &&
|
|
97
|
-
manifest.mode !== 'debug'
|
|
98
|
-
) {
|
|
99
|
-
throw Fail`State-sync manifest missing historical artifacts`;
|
|
100
|
-
}
|
|
143
|
+
const artifacts = harden(Object.fromEntries(manifest.artifacts || []));
|
|
101
144
|
|
|
102
145
|
// Represent the data in `exportDir` as a SwingSetExporter object.
|
|
103
146
|
/** @type {import('@agoric/swing-store').SwingStoreExporter} */
|
|
@@ -128,7 +171,7 @@ export const performStateSyncImport = async (
|
|
|
128
171
|
log?.(`importing artifact ${name}`);
|
|
129
172
|
const fileName = artifacts[name];
|
|
130
173
|
if (!fileName) {
|
|
131
|
-
Fail`invalid artifact ${name}`;
|
|
174
|
+
Fail`invalid artifact ${q(name)}`;
|
|
132
175
|
}
|
|
133
176
|
const stream = createReadStream(safeExportFileResolve(fileName));
|
|
134
177
|
yield* stream;
|
|
@@ -141,13 +184,47 @@ export const performStateSyncImport = async (
|
|
|
141
184
|
},
|
|
142
185
|
});
|
|
143
186
|
|
|
144
|
-
|
|
187
|
+
if (exportDataMode === 'all') {
|
|
188
|
+
const importOptions = checkAndGetImportSwingStoreOptions(
|
|
189
|
+
{ artifactMode, exportDataMode },
|
|
190
|
+
manifest,
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
const swingstore = await importDB(exporter, stateDir, importOptions);
|
|
194
|
+
|
|
195
|
+
const { hostStorage } = swingstore;
|
|
196
|
+
|
|
197
|
+
hostStorage.kvStore.set('host.height', String(manifest.blockHeight));
|
|
198
|
+
await hostStorage.commit();
|
|
199
|
+
await hostStorage.close();
|
|
200
|
+
} else if (exportDataMode === 'repair-metadata') {
|
|
201
|
+
blockHeight !== 0 || Fail`repair metadata requires a block height`;
|
|
202
|
+
|
|
203
|
+
manifest.data || Fail`State-sync manifest missing export data`;
|
|
204
|
+
|
|
205
|
+
artifactMode === 'none' ||
|
|
206
|
+
Fail`Cannot restore artifacts while repairing metadata`;
|
|
207
|
+
|
|
208
|
+
const { hostStorage } = openDB(stateDir);
|
|
209
|
+
|
|
210
|
+
const savedBlockHeight =
|
|
211
|
+
Number(hostStorage.kvStore.get('host.height')) || 0;
|
|
145
212
|
|
|
146
|
-
|
|
213
|
+
if (blockHeight !== savedBlockHeight) {
|
|
214
|
+
throw Fail`block height doesn't match. requested=${q(
|
|
215
|
+
blockHeight,
|
|
216
|
+
)}, current=${q(savedBlockHeight)}`;
|
|
217
|
+
}
|
|
147
218
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
219
|
+
await hostStorage.repairMetadata(exporter);
|
|
220
|
+
|
|
221
|
+
await hostStorage.commit();
|
|
222
|
+
await hostStorage.close();
|
|
223
|
+
} else if (exportDataMode === 'skip') {
|
|
224
|
+
throw Fail`Repopulation of artifacts not yet supported`;
|
|
225
|
+
} else {
|
|
226
|
+
throw Fail`Unknown export-data-mode ${exportDataMode}`;
|
|
227
|
+
}
|
|
151
228
|
};
|
|
152
229
|
|
|
153
230
|
/**
|
|
@@ -182,9 +259,20 @@ export const main = async (
|
|
|
182
259
|
/** @type {string} */ (processValue.getFlag('export-dir', '.')),
|
|
183
260
|
);
|
|
184
261
|
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
262
|
+
const artifactMode =
|
|
263
|
+
/** @type {import('./export-kernel-db.js').SwingStoreArtifactMode | undefined} */ (
|
|
264
|
+
processValue.getFlag('artifact-mode')
|
|
265
|
+
);
|
|
266
|
+
checkArtifactMode(artifactMode);
|
|
267
|
+
|
|
268
|
+
const exportDataMode = processValue.getFlag('export-data-mode');
|
|
269
|
+
checkExportDataMode(exportDataMode, true);
|
|
270
|
+
|
|
271
|
+
if (
|
|
272
|
+
processValue.getBoolean({ flagName: 'include-historical' }) !== undefined
|
|
273
|
+
) {
|
|
274
|
+
throw Fail`deprecated "include-historical" options, use "artifact-mode" instead`;
|
|
275
|
+
}
|
|
188
276
|
|
|
189
277
|
const checkBlockHeight = processValue.getInteger({
|
|
190
278
|
flagName: 'check-block-height',
|
|
@@ -199,7 +287,8 @@ export const main = async (
|
|
|
199
287
|
stateDir,
|
|
200
288
|
exportDir,
|
|
201
289
|
blockHeight: checkBlockHeight,
|
|
202
|
-
|
|
290
|
+
artifactMode,
|
|
291
|
+
exportDataMode,
|
|
203
292
|
},
|
|
204
293
|
{
|
|
205
294
|
fs,
|