@agoric/cosmic-swingset 0.41.4-dev-c6d8a27.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 +98 -46
- package/src/import-kernel-db.js +125 -40
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
|
@@ -23,30 +23,64 @@ import { makeProcessValue } from './helpers/process-value.js';
|
|
|
23
23
|
// with the golang SwingStoreExportsHandler in golang/cosmos/x/swingset/keeper/swing_store_exports_handler.go
|
|
24
24
|
export const ExportManifestFileName = 'export-manifest.json';
|
|
25
25
|
|
|
26
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* @typedef {'none' // No artifacts included
|
|
28
|
+
* | import("@agoric/swing-store").ArtifactMode
|
|
29
|
+
* } SwingStoreArtifactMode
|
|
30
|
+
*/
|
|
27
31
|
|
|
28
32
|
/**
|
|
29
|
-
* @
|
|
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
|
|
30
41
|
* @returns {import("@agoric/swing-store").ArtifactMode}
|
|
31
42
|
*/
|
|
32
|
-
const
|
|
33
|
-
switch (
|
|
34
|
-
case '
|
|
35
|
-
case
|
|
43
|
+
export const getEffectiveArtifactMode = artifactMode => {
|
|
44
|
+
switch (artifactMode) {
|
|
45
|
+
case 'none':
|
|
46
|
+
case 'operational':
|
|
36
47
|
return 'operational';
|
|
48
|
+
case undefined:
|
|
49
|
+
case 'replay':
|
|
50
|
+
return 'replay';
|
|
37
51
|
case 'archival':
|
|
38
|
-
return 'archival';
|
|
39
52
|
case 'debug':
|
|
40
|
-
return
|
|
53
|
+
return artifactMode;
|
|
41
54
|
default:
|
|
42
|
-
throw Fail`Invalid value ${q(
|
|
55
|
+
throw Fail`Invalid value ${q(artifactMode)} for "artifact-mode"`;
|
|
43
56
|
}
|
|
44
57
|
};
|
|
45
58
|
|
|
59
|
+
/** @type {(artifactMode: string | undefined) => asserts artifactMode is SwingStoreArtifactMode | undefined} */
|
|
60
|
+
export const checkArtifactMode = getEffectiveArtifactMode;
|
|
61
|
+
|
|
46
62
|
/**
|
|
47
|
-
* @
|
|
63
|
+
* @param {string | undefined} mode
|
|
64
|
+
* @param {boolean} [isImport]
|
|
65
|
+
* @returns {asserts mode is SwingStoreExportDataMode | undefined}
|
|
48
66
|
*/
|
|
49
|
-
const
|
|
67
|
+
export const checkExportDataMode = (mode, isImport = false) => {
|
|
68
|
+
switch (mode) {
|
|
69
|
+
case 'skip':
|
|
70
|
+
case undefined:
|
|
71
|
+
break;
|
|
72
|
+
case 'all':
|
|
73
|
+
break;
|
|
74
|
+
case 'repair-metadata': {
|
|
75
|
+
if (isImport) {
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
// Fall through
|
|
79
|
+
}
|
|
80
|
+
default:
|
|
81
|
+
throw Fail`Invalid value ${q(mode)} for "export-data-mode"`;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
50
84
|
|
|
51
85
|
/**
|
|
52
86
|
* A state-sync manifest is a representation of the information contained in a
|
|
@@ -60,7 +94,7 @@ const checkExportMode = getArtifactModeFromExportMode;
|
|
|
60
94
|
*
|
|
61
95
|
* @typedef {object} StateSyncManifest
|
|
62
96
|
* @property {number} blockHeight the block height corresponding to this export
|
|
63
|
-
* @property {
|
|
97
|
+
* @property {SwingStoreArtifactMode} [artifactMode]
|
|
64
98
|
* @property {string} [data] file name containing the swingStore "export data"
|
|
65
99
|
* @property {Array<[artifactName: string, fileName: string]>} artifacts
|
|
66
100
|
* List of swingStore export artifacts which can be validated by the export data
|
|
@@ -79,8 +113,8 @@ const checkExportMode = getArtifactModeFromExportMode;
|
|
|
79
113
|
* @property {string} stateDir the directory containing the SwingStore to export
|
|
80
114
|
* @property {string} exportDir the directory in which to place the exported artifacts and manifest
|
|
81
115
|
* @property {number} [blockHeight] block height to check for
|
|
82
|
-
* @property {
|
|
83
|
-
* @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
|
|
84
118
|
*/
|
|
85
119
|
|
|
86
120
|
/**
|
|
@@ -96,10 +130,12 @@ export const validateExporterOptions = options => {
|
|
|
96
130
|
options.blockHeight == null ||
|
|
97
131
|
typeof options.blockHeight === 'number' ||
|
|
98
132
|
Fail`optional blockHeight option not a number`;
|
|
99
|
-
|
|
100
|
-
options.
|
|
101
|
-
|
|
102
|
-
|
|
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`;
|
|
103
139
|
};
|
|
104
140
|
|
|
105
141
|
/**
|
|
@@ -113,7 +149,7 @@ export const validateExporterOptions = options => {
|
|
|
113
149
|
* @returns {StateSyncExporter}
|
|
114
150
|
*/
|
|
115
151
|
export const initiateSwingStoreExport = (
|
|
116
|
-
{ stateDir, exportDir, blockHeight,
|
|
152
|
+
{ stateDir, exportDir, blockHeight, artifactMode, exportDataMode },
|
|
117
153
|
{
|
|
118
154
|
fs: { open, writeFile },
|
|
119
155
|
pathResolve,
|
|
@@ -122,8 +158,7 @@ export const initiateSwingStoreExport = (
|
|
|
122
158
|
log = console.log,
|
|
123
159
|
},
|
|
124
160
|
) => {
|
|
125
|
-
const
|
|
126
|
-
|
|
161
|
+
const effectiveArtifactMode = getEffectiveArtifactMode(artifactMode);
|
|
127
162
|
/** @type {number | undefined} */
|
|
128
163
|
let savedBlockHeight;
|
|
129
164
|
|
|
@@ -143,7 +178,9 @@ export const initiateSwingStoreExport = (
|
|
|
143
178
|
const manifestFile = await open(manifestPath, 'wx');
|
|
144
179
|
cleanup.push(async () => manifestFile.close());
|
|
145
180
|
|
|
146
|
-
const swingStoreExporter = makeExporter(stateDir, {
|
|
181
|
+
const swingStoreExporter = makeExporter(stateDir, {
|
|
182
|
+
artifactMode: effectiveArtifactMode,
|
|
183
|
+
});
|
|
147
184
|
cleanup.push(async () => swingStoreExporter.close());
|
|
148
185
|
|
|
149
186
|
const { hostStorage } = openDB(stateDir);
|
|
@@ -153,7 +190,9 @@ export const initiateSwingStoreExport = (
|
|
|
153
190
|
|
|
154
191
|
if (blockHeight) {
|
|
155
192
|
blockHeight === savedBlockHeight ||
|
|
156
|
-
Fail`DB at unexpected block height ${savedBlockHeight} (expected ${
|
|
193
|
+
Fail`DB at unexpected block height ${q(savedBlockHeight)} (expected ${q(
|
|
194
|
+
blockHeight,
|
|
195
|
+
)})`;
|
|
157
196
|
}
|
|
158
197
|
|
|
159
198
|
abortIfStopped();
|
|
@@ -163,11 +202,11 @@ export const initiateSwingStoreExport = (
|
|
|
163
202
|
/** @type {StateSyncManifest} */
|
|
164
203
|
const manifest = {
|
|
165
204
|
blockHeight: savedBlockHeight,
|
|
166
|
-
|
|
205
|
+
artifactMode: artifactMode || effectiveArtifactMode,
|
|
167
206
|
artifacts: [],
|
|
168
207
|
};
|
|
169
208
|
|
|
170
|
-
if (
|
|
209
|
+
if (exportDataMode === 'all') {
|
|
171
210
|
log?.(`Writing Export Data`);
|
|
172
211
|
const fileName = `export-data.jsonl`;
|
|
173
212
|
const exportDataFile = await open(pathResolve(exportDir, fileName), 'wx');
|
|
@@ -181,14 +220,16 @@ export const initiateSwingStoreExport = (
|
|
|
181
220
|
}
|
|
182
221
|
abortIfStopped();
|
|
183
222
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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
|
+
}
|
|
192
233
|
}
|
|
193
234
|
|
|
194
235
|
await manifestFile.write(JSON.stringify(manifest, null, 2));
|
|
@@ -272,11 +313,22 @@ export const main = async (
|
|
|
272
313
|
/** @type {string} */ (processValue.getFlag('export-dir', '.')),
|
|
273
314
|
);
|
|
274
315
|
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
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
|
+
}
|
|
280
332
|
|
|
281
333
|
const checkBlockHeight = processValue.getInteger({
|
|
282
334
|
flagName: 'check-block-height',
|
|
@@ -293,8 +345,8 @@ export const main = async (
|
|
|
293
345
|
stateDir,
|
|
294
346
|
exportDir,
|
|
295
347
|
blockHeight: checkBlockHeight,
|
|
296
|
-
|
|
297
|
-
|
|
348
|
+
artifactMode,
|
|
349
|
+
exportDataMode,
|
|
298
350
|
},
|
|
299
351
|
{
|
|
300
352
|
fs,
|
|
@@ -335,7 +387,7 @@ export const main = async (
|
|
|
335
387
|
* @returns {StateSyncExporter}
|
|
336
388
|
*/
|
|
337
389
|
export const spawnSwingStoreExport = (
|
|
338
|
-
{ stateDir, exportDir, blockHeight,
|
|
390
|
+
{ stateDir, exportDir, blockHeight, artifactMode, exportDataMode },
|
|
339
391
|
{ fork, verbose },
|
|
340
392
|
) => {
|
|
341
393
|
const args = ['--state-dir', stateDir, '--export-dir', exportDir];
|
|
@@ -344,12 +396,12 @@ export const spawnSwingStoreExport = (
|
|
|
344
396
|
args.push('--check-block-height', String(blockHeight));
|
|
345
397
|
}
|
|
346
398
|
|
|
347
|
-
if (
|
|
348
|
-
args.push('--
|
|
399
|
+
if (artifactMode) {
|
|
400
|
+
args.push('--artifact-mode', artifactMode);
|
|
349
401
|
}
|
|
350
402
|
|
|
351
|
-
if (
|
|
352
|
-
args.push('--
|
|
403
|
+
if (exportDataMode) {
|
|
404
|
+
args.push('--export-data-mode', exportDataMode);
|
|
353
405
|
}
|
|
354
406
|
|
|
355
407
|
if (verbose) {
|
|
@@ -401,7 +453,7 @@ export const spawnSwingStoreExport = (
|
|
|
401
453
|
}
|
|
402
454
|
default: {
|
|
403
455
|
// @ts-expect-error exhaustive check
|
|
404
|
-
Fail`Unexpected ${msg.type} message`;
|
|
456
|
+
Fail`Unexpected ${q(msg.type)} message`;
|
|
405
457
|
}
|
|
406
458
|
}
|
|
407
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 ${
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (!manifest.data) {
|
|
85
|
-
throw Fail`State-sync manifest missing export data`;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (!manifest.artifacts) {
|
|
89
|
-
throw Fail`State-sync manifest missing required artifacts`;
|
|
138
|
+
Fail`State-sync manifest for unexpected block height ${q(
|
|
139
|
+
manifest.blockHeight,
|
|
140
|
+
)} (expected ${q(blockHeight)})`;
|
|
90
141
|
}
|
|
91
142
|
|
|
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,17 +184,47 @@ export const performStateSyncImport = async (
|
|
|
141
184
|
},
|
|
142
185
|
});
|
|
143
186
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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);
|
|
147
209
|
|
|
148
|
-
|
|
210
|
+
const savedBlockHeight =
|
|
211
|
+
Number(hostStorage.kvStore.get('host.height')) || 0;
|
|
149
212
|
|
|
150
|
-
|
|
213
|
+
if (blockHeight !== savedBlockHeight) {
|
|
214
|
+
throw Fail`block height doesn't match. requested=${q(
|
|
215
|
+
blockHeight,
|
|
216
|
+
)}, current=${q(savedBlockHeight)}`;
|
|
217
|
+
}
|
|
151
218
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
+
}
|
|
155
228
|
};
|
|
156
229
|
|
|
157
230
|
/**
|
|
@@ -186,9 +259,20 @@ export const main = async (
|
|
|
186
259
|
/** @type {string} */ (processValue.getFlag('export-dir', '.')),
|
|
187
260
|
);
|
|
188
261
|
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
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
|
+
}
|
|
192
276
|
|
|
193
277
|
const checkBlockHeight = processValue.getInteger({
|
|
194
278
|
flagName: 'check-block-height',
|
|
@@ -203,7 +287,8 @@ export const main = async (
|
|
|
203
287
|
stateDir,
|
|
204
288
|
exportDir,
|
|
205
289
|
blockHeight: checkBlockHeight,
|
|
206
|
-
|
|
290
|
+
artifactMode,
|
|
291
|
+
exportDataMode,
|
|
207
292
|
},
|
|
208
293
|
{
|
|
209
294
|
fs,
|