@agoric/cosmic-swingset 0.41.4-dev-fe66674.0 → 0.41.4-dev-85bac81.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agoric/cosmic-swingset",
3
- "version": "0.41.4-dev-fe66674.0+fe66674",
3
+ "version": "0.41.4-dev-85bac81.0+85bac81",
4
4
  "description": "Agoric's Cosmos blockchain integration",
5
5
  "type": "module",
6
6
  "bin": {
@@ -22,18 +22,19 @@
22
22
  "author": "Agoric",
23
23
  "license": "Apache-2.0",
24
24
  "dependencies": {
25
- "@agoric/builders": "0.1.1-dev-fe66674.0+fe66674",
26
- "@agoric/cosmos": "0.34.2-dev-fe66674.0+fe66674",
27
- "@agoric/deploy-script-support": "0.10.4-dev-fe66674.0+fe66674",
28
- "@agoric/internal": "0.3.3-dev-fe66674.0+fe66674",
29
- "@agoric/store": "0.9.3-dev-fe66674.0+fe66674",
30
- "@agoric/swing-store": "0.9.2-dev-fe66674.0+fe66674",
31
- "@agoric/swingset-vat": "0.32.3-dev-fe66674.0+fe66674",
32
- "@agoric/telemetry": "0.6.3-dev-fe66674.0+fe66674",
33
- "@agoric/vm-config": "0.1.1-dev-fe66674.0+fe66674",
25
+ "@agoric/builders": "0.1.1-dev-85bac81.0+85bac81",
26
+ "@agoric/cosmos": "0.34.2-dev-85bac81.0+85bac81",
27
+ "@agoric/deploy-script-support": "0.10.4-dev-85bac81.0+85bac81",
28
+ "@agoric/internal": "0.3.3-dev-85bac81.0+85bac81",
29
+ "@agoric/store": "0.9.3-dev-85bac81.0+85bac81",
30
+ "@agoric/swing-store": "0.9.2-dev-85bac81.0+85bac81",
31
+ "@agoric/swingset-vat": "0.32.3-dev-85bac81.0+85bac81",
32
+ "@agoric/telemetry": "0.6.3-dev-85bac81.0+85bac81",
33
+ "@agoric/vm-config": "0.1.1-dev-85bac81.0+85bac81",
34
34
  "@endo/bundle-source": "^3.5.1",
35
35
  "@endo/env-options": "^1.1.8",
36
36
  "@endo/errors": "^1.2.9",
37
+ "@endo/eventual-send": "^1.3.0",
37
38
  "@endo/far": "^1.1.10",
38
39
  "@endo/import-bundle": "^1.3.3",
39
40
  "@endo/init": "^1.1.8",
@@ -47,6 +48,7 @@
47
48
  "anylogger": "^0.21.0",
48
49
  "deterministic-json": "^1.0.5",
49
50
  "import-meta-resolve": "^2.2.1",
51
+ "ses": "^1.11.0",
50
52
  "tmp": "^0.2.1"
51
53
  },
52
54
  "devDependencies": {
@@ -71,5 +73,5 @@
71
73
  "typeCoverage": {
72
74
  "atLeast": 83.4
73
75
  },
74
- "gitHead": "fe666748e6b4ff8f8152eb77740fb6dd0cef5b83"
76
+ "gitHead": "85bac810ac4684978b3fac16cea9af04996cc9f1"
75
77
  }
package/src/chain-main.js CHANGED
@@ -112,6 +112,28 @@ const validateSwingsetConfig = swingsetConfig => {
112
112
  Fail`maxVatsOnline must be a positive integer`;
113
113
  };
114
114
 
115
+ /**
116
+ * Capture "port numbers" for communicating with cosmos modules.
117
+ *
118
+ * @param {object} action
119
+ */
120
+ export const extractPortNums = action => {
121
+ const portNums = {};
122
+ for (const [key, value] of Object.entries(action)) {
123
+ const portAlias = CosmosInitKeyToBridgeId[key];
124
+ if (portAlias) {
125
+ // Use the alias if it exists.
126
+ portNums[portAlias] = value;
127
+ } else if (key.endsWith(PORT_SUFFIX)) {
128
+ // Anything else that ends in the suffix is assumed to be a port
129
+ // number, as described in app.go/cosmosInitAction.
130
+ const portName = key.slice(0, key.length - PORT_SUFFIX.length);
131
+ portNums[portName] = value;
132
+ }
133
+ }
134
+ return harden(portNums);
135
+ };
136
+
115
137
  /**
116
138
  * @template {unknown} [T=unknown]
117
139
  * @param {(req: string) => string} call
@@ -174,88 +196,57 @@ const makePrefixedBridgeStorage = (
174
196
  });
175
197
  };
176
198
 
177
- export default async function main(
178
- progname,
179
- args,
180
- { env, homedir, path = nativePath, agcc },
181
- ) {
182
- const portNums = {};
183
-
184
- // TODO: use the 'basedir' pattern
185
-
186
- const processValue = makeProcessValue({ env, args });
187
-
188
- // We try to find the actual cosmos state directory (default=~/.ag-chain-cosmos), which
189
- // is better than scribbling into the current directory.
190
- const cosmosHome = processValue.getFlag(
191
- 'home',
192
- `${homedir}/.ag-chain-cosmos`,
199
+ /**
200
+ * @param {(req: string) => string} call
201
+ * @param {string} queuePath
202
+ */
203
+ export const makeQueueStorage = (call, queuePath) => {
204
+ const { kvStore, commit, abort } = makeBufferedStorage(
205
+ makePrefixedBridgeStorage(
206
+ call,
207
+ `${queuePath}.`,
208
+ 'setWithoutNotify',
209
+ x => x,
210
+ x => x,
211
+ ),
193
212
  );
194
- const stateDBDir = `${cosmosHome}/data/agoric`;
195
- fs.mkdirSync(stateDBDir, { recursive: true });
196
-
197
- // console.log('Have AG_COSMOS', agcc);
198
-
199
- const portHandlers = {};
200
- let lastPort = 0;
201
- function registerPortHandler(portHandler) {
202
- lastPort += 1;
203
- const port = lastPort;
204
- portHandlers[port] = async (...phArgs) =>
205
- E.resolve(portHandler(...phArgs)).catch(e => {
206
- console.error('portHandler threw', e);
207
- throw e;
208
- });
209
- return port;
210
- }
211
-
212
- function fromGo(port, str, replier) {
213
- // console.error(`inbound ${port} ${str}`);
214
- const handler = portHandlers[port];
215
- if (!handler) {
216
- replier.reject(`invalid requested port ${port}`);
217
- return;
218
- }
219
- const action = JSON.parse(str);
220
- const p = Promise.resolve(handler(action));
221
- void E.when(
222
- p,
223
- res => {
224
- // console.error(`Replying in Node to ${str} with`, res);
225
- replier.resolve(stringify(res !== undefined ? res : null));
226
- },
227
- rej => {
228
- // console.error(`Rejecting in Node to ${str} with`, rej);
229
- replier.reject(`${(rej && rej.stack) || rej}`);
230
- },
231
- );
232
- }
233
-
234
- // Actually run the main ag-chain-cosmos program. Before we start the daemon,
235
- // there will be a call to nodePort/AG_COSMOS_INIT, otherwise exit.
236
- const nodePort = registerPortHandler(toSwingSet);
237
-
238
- // Need to keep the process alive until Go exits.
239
- whenHellFreezesOver = new Promise(() => {});
240
- agcc.runAgCosmosDaemon(nodePort, fromGo, [progname, ...args]);
241
-
242
- /**
243
- * @type {undefined | {
244
- * blockHeight: number,
245
- * exporter?: import('./export-kernel-db.js').StateSyncExporter,
246
- * exportDir?: string,
247
- * cleanup?: () => Promise<void>,
248
- * }}
249
- */
250
- let stateSyncExport;
251
-
252
- async function discardStateSyncExport() {
253
- const exportData = stateSyncExport;
254
- stateSyncExport = undefined;
255
- await exportData?.exporter?.stop();
256
- await exportData?.cleanup?.();
257
- }
213
+ return harden({ ...kvStore, commit, abort });
214
+ };
258
215
 
216
+ /**
217
+ * @param {any} agcc
218
+ * @param {string} stateDBDir
219
+ * @param {object} options
220
+ * @param {typeof process.env} [options.env]
221
+ * @param {Pick<import('fs'), 'createWriteStream' | 'mkdirSync' | 'renameSync'>} options.fs
222
+ * @param {Pick<import('path'), 'join' | 'resolve'>} options.path
223
+ * @param {import('tmp')} [options.tmp] required to support vatSnapshotArchiveDir/vatTranscriptArchiveDir
224
+ * @param {ReturnType<typeof makeProcessValue>} [options.processValue]
225
+ * @param {() => Promise<void>} [options.readyForCommit]
226
+ * @param {{
227
+ * debugName?: string,
228
+ * slogSender?: ERef<EReturn<typeof makeSlogSender>>,
229
+ * swingStore?: import('@agoric/swing-store').SwingStore,
230
+ * vatconfig?: Parameters<typeof launch>[0]['vatconfig'],
231
+ * }} [options.testingOverrides]
232
+ */
233
+ export const makeLaunchChain = (
234
+ agcc,
235
+ stateDBDir,
236
+ {
237
+ env = {},
238
+ // eslint-disable-next-line no-shadow
239
+ fs,
240
+ path,
241
+ // eslint-disable-next-line no-shadow
242
+ tmp,
243
+ processValue = makeProcessValue({ env, args: [] }),
244
+ readyForCommit,
245
+ testingOverrides = {},
246
+ },
247
+ ) => {
248
+ /** @typedef {[args: Parameters<typeof agcc.send>, ret: ReturnType<typeof agcc.send>]} SavedChainSend */
249
+ /** @type {SavedChainSend[]} */
259
250
  let savedChainSends = [];
260
251
 
261
252
  // Send a chain downcall, recording what we sent and received.
@@ -266,8 +257,10 @@ export default async function main(
266
257
  }
267
258
 
268
259
  const clearChainSends = async () => {
269
- // Cosmos should have blocked before calling commit, but wait just in case
270
- await stateSyncExport?.exporter?.onStarted().catch(ignore);
260
+ // TODO: Make `readyForCommit` an explicit `launch` input rather than
261
+ // having an overloaded async `clearChainSends` with the expectation that
262
+ // it is called right before `commit()`.
263
+ await readyForCommit?.();
271
264
 
272
265
  const chainSends = savedChainSends;
273
266
  savedChainSends = [];
@@ -282,7 +275,9 @@ export default async function main(
282
275
 
283
276
  // Just send all the things we saved.
284
277
  while (chainSends.length > 0) {
285
- const [sendArgs, expectedRet] = chainSends.shift();
278
+ const [sendArgs, expectedRet] = /** @type {SavedChainSend} */ (
279
+ chainSends.shift()
280
+ );
286
281
  const actualRet = agcc.send(...sendArgs);
287
282
 
288
283
  // Enforce that we got back what we expected.
@@ -296,14 +291,9 @@ export default async function main(
296
291
  }
297
292
  }
298
293
 
299
- /** @type {((obj: object) => void) | undefined} */
300
- let writeSlogObject;
301
-
302
- // In the past, storagePort could change with every message. It's defined out
303
- // here so 'sendToChainStorage' can close over the single mutable instance,
304
- // when we updated the 'portNums.storage' value each time toSwingSet was called.
305
- async function launchAndInitializeSwingSet(initAction) {
306
- const { XSNAP_KEEP_SNAPSHOTS, NODE_HEAP_SNAPSHOTS = -1 } = env;
294
+ const launchChain = async initAction => {
295
+ const { XSNAP_KEEP_SNAPSHOTS = '', NODE_HEAP_SNAPSHOTS = '-1' } = env;
296
+ const portNums = extractPortNums(initAction);
307
297
 
308
298
  /** @type {CosmosSwingsetConfig} */
309
299
  const swingsetConfig = harden(initAction.resolvedConfig || {});
@@ -342,20 +332,12 @@ export default async function main(
342
332
  val => stringify(exportMailbox(val)),
343
333
  ),
344
334
  );
345
- const makeQueueStorage = queuePath => {
346
- const { kvStore, commit, abort } = makeBufferedStorage(
347
- makePrefixedBridgeStorage(
348
- sendToChainStorage,
349
- `${queuePath}.`,
350
- 'setWithoutNotify',
351
- x => x,
352
- x => x,
353
- ),
354
- );
355
- return harden({ ...kvStore, commit, abort });
356
- };
357
- const actionQueueStorage = makeQueueStorage(STORAGE_PATH.ACTION_QUEUE);
335
+ const actionQueueStorage = makeQueueStorage(
336
+ sendToChainStorage,
337
+ STORAGE_PATH.ACTION_QUEUE,
338
+ );
358
339
  const highPriorityQueueStorage = makeQueueStorage(
340
+ sendToChainStorage,
359
341
  STORAGE_PATH.HIGH_PRIORITY_QUEUE,
360
342
  );
361
343
  /**
@@ -451,20 +433,18 @@ export default async function main(
451
433
  return pathname;
452
434
  };
453
435
 
454
- // Delay makeShutdown to override the golang interrupts
455
- const { registerShutdown } = makeShutdown();
456
-
457
436
  const { metricsProvider } = getTelemetryProviders({
458
437
  console,
459
438
  env,
460
439
  serviceName: TELEMETRY_SERVICE_NAME,
461
440
  });
462
441
 
463
- const slogSender = await makeSlogSender({
464
- stateDir: stateDBDir,
465
- env,
466
- serviceName: TELEMETRY_SERVICE_NAME,
467
- });
442
+ const slogSender = await (testingOverrides.slogSender ||
443
+ makeSlogSender({
444
+ stateDir: stateDBDir,
445
+ env,
446
+ serviceName: TELEMETRY_SERVICE_NAME,
447
+ }));
468
448
 
469
449
  const swingStoreTraceFile = processValue.getPath({
470
450
  envName: 'SWING_STORE_TRACE',
@@ -546,19 +526,23 @@ export default async function main(
546
526
  const s = await launch({
547
527
  actionQueueStorage,
548
528
  highPriorityQueueStorage,
549
- kernelStateDBDir: stateDBDir,
529
+ swingStore: testingOverrides.swingStore,
530
+ kernelStateDBDir: testingOverrides.swingStore ? undefined : stateDBDir,
550
531
  makeInstallationPublisher,
551
532
  mailboxStorage,
552
533
  clearChainSends,
553
534
  replayChainSends,
554
535
  bridgeOutbound: doOutboundBridge,
555
- vatconfig: getVatConfig,
536
+ vatconfig: testingOverrides.vatconfig || getVatConfig,
556
537
  argv,
557
538
  env,
558
539
  verboseBlocks: true,
559
540
  metricsProvider,
541
+ debugName: testingOverrides.debugName,
560
542
  slogSender,
561
- swingStoreExportCallback,
543
+ swingStoreExportCallback: testingOverrides.swingStore
544
+ ? undefined
545
+ : swingStoreExportCallback,
562
546
  swingStoreTraceFile,
563
547
  keepSnapshots,
564
548
  keepTranscripts,
@@ -567,30 +551,94 @@ export default async function main(
567
551
  afterCommitCallback,
568
552
  swingsetConfig,
569
553
  });
554
+ savedChainSends = s.savedChainSends;
555
+ return s;
556
+ };
570
557
 
571
- const { blockingSend, shutdown } = s;
572
- ({ writeSlogObject, savedChainSends } = s);
558
+ return launchChain;
559
+ };
573
560
 
574
- let pendingBlockingSend = Promise.resolve();
561
+ export default async function main(
562
+ progname,
563
+ args,
564
+ { env, homedir, path = nativePath, agcc },
565
+ ) {
566
+ // TODO: use the 'basedir' pattern
575
567
 
576
- registerShutdown(async interrupted => {
577
- await Promise.all([
578
- interrupted && pendingBlockingSend.then(shutdown),
579
- discardStateSyncExport(),
580
- ]);
581
- });
568
+ const processValue = makeProcessValue({ env, args });
582
569
 
583
- const blockingSendSpy = async action => {
584
- const result = blockingSend(action);
585
- pendingBlockingSend = Promise.resolve(result).then(ignore, ignore);
586
- return result;
587
- };
588
- return blockingSendSpy;
589
- }
570
+ // We try to find the actual cosmos state directory (default=~/.ag-chain-cosmos), which
571
+ // is better than scribbling into the current directory.
572
+ const cosmosHome = processValue.getFlag(
573
+ 'home',
574
+ `${homedir}/.ag-chain-cosmos`,
575
+ );
576
+ const stateDBDir = `${cosmosHome}/data/agoric`;
577
+ fs.mkdirSync(stateDBDir, { recursive: true });
590
578
 
591
579
  /** @type {EReturn<typeof launch>['blockingSend'] | undefined} */
592
580
  let blockingSend;
593
581
 
582
+ const portHandlers = {};
583
+ let lastPort = 0;
584
+ function registerPortHandler(portHandler) {
585
+ lastPort += 1;
586
+ const port = lastPort;
587
+ portHandlers[port] = async (...phArgs) =>
588
+ E.resolve(portHandler(...phArgs)).catch(e => {
589
+ console.error('portHandler threw', e);
590
+ throw e;
591
+ });
592
+ return port;
593
+ }
594
+
595
+ function fromGo(port, str, replier) {
596
+ // console.error(`inbound ${port} ${str}`);
597
+ const handler = portHandlers[port];
598
+ if (!handler) {
599
+ replier.reject(`invalid requested port ${port}`);
600
+ return;
601
+ }
602
+ const action = JSON.parse(str);
603
+ const p = Promise.resolve(handler(action));
604
+ void E.when(
605
+ p,
606
+ res => {
607
+ // console.error(`Replying in Node to ${str} with`, res);
608
+ replier.resolve(stringify(res !== undefined ? res : null));
609
+ },
610
+ rej => {
611
+ // console.error(`Rejecting in Node to ${str} with`, rej);
612
+ replier.reject(`${(rej && rej.stack) || rej}`);
613
+ },
614
+ );
615
+ }
616
+
617
+ // Actually run the main ag-chain-cosmos program. Before we start the daemon,
618
+ // there will be a call to nodePort/AG_COSMOS_INIT, otherwise exit.
619
+ const nodePort = registerPortHandler(toSwingSet);
620
+
621
+ // Need to keep the process alive until Go exits.
622
+ whenHellFreezesOver = new Promise(() => {});
623
+ agcc.runAgCosmosDaemon(nodePort, fromGo, [progname, ...args]);
624
+
625
+ /**
626
+ * @type {undefined | {
627
+ * blockHeight: number,
628
+ * exporter?: import('./export-kernel-db.js').StateSyncExporter,
629
+ * exportDir?: string,
630
+ * cleanup?: () => Promise<void>,
631
+ * }}
632
+ */
633
+ let stateSyncExport;
634
+
635
+ async function discardStateSyncExport() {
636
+ const exportData = stateSyncExport;
637
+ stateSyncExport = undefined;
638
+ await exportData?.exporter?.stop();
639
+ await exportData?.cleanup?.();
640
+ }
641
+
594
642
  async function handleSwingStoreExport(blockHeight, request, requestArgs) {
595
643
  await null;
596
644
  switch (request) {
@@ -729,6 +777,19 @@ export default async function main(
729
777
  }
730
778
  }
731
779
 
780
+ const launchChain = makeLaunchChain(agcc, stateDBDir, {
781
+ env,
782
+ fs,
783
+ path,
784
+ tmp,
785
+ processValue,
786
+ readyForCommit: async () =>
787
+ stateSyncExport?.exporter?.onStarted().then(ignore, ignore),
788
+ });
789
+
790
+ /** @type {((obj: object) => void) | undefined} */
791
+ let writeSlogObject;
792
+
732
793
  async function toSwingSet(action, _replier) {
733
794
  // console.log(`toSwingSet`, action);
734
795
 
@@ -736,27 +797,27 @@ export default async function main(
736
797
 
737
798
  switch (action.type) {
738
799
  case ActionType.AG_COSMOS_INIT: {
739
- // console.error('got AG_COSMOS_INIT', action);
740
-
741
800
  !blockingSend || Fail`Swingset already initialized`;
742
801
 
743
- // Capture "port numbers" for communicating with cosmos modules.
744
- for (const [key, value] of Object.entries(action)) {
745
- const portAlias = CosmosInitKeyToBridgeId[key];
746
- if (portAlias) {
747
- // Use the alias if it exists.
748
- portNums[portAlias] = value;
749
- } else if (key.endsWith(PORT_SUFFIX)) {
750
- // Anything else that ends in the suffix is assumed to be a port
751
- // number, as described in app.go/cosmosInitAction.
752
- const portName = key.slice(0, key.length - PORT_SUFFIX.length);
753
- portNums[portName] = value;
754
- }
755
- }
756
- harden(portNums);
757
-
758
- // Ensure that initialization has completed.
759
- blockingSend = await launchAndInitializeSwingSet(action);
802
+ const s = await launchChain(action);
803
+ const { blockingSend: sendToSwingset, shutdown } = s;
804
+ ({ writeSlogObject } = s);
805
+
806
+ // Wrap `blockingSend` with a spy for supporting clean shutdowns.
807
+ const { registerShutdown } = makeShutdown();
808
+ let pendingBlockingSend = Promise.resolve();
809
+ registerShutdown(async interrupted => {
810
+ await Promise.all([
811
+ interrupted && pendingBlockingSend.then(shutdown),
812
+ discardStateSyncExport(),
813
+ ]);
814
+ });
815
+ // eslint-disable-next-line no-shadow
816
+ blockingSend = async action => {
817
+ const result = sendToSwingset(action);
818
+ pendingBlockingSend = Promise.resolve(result).then(ignore, ignore);
819
+ return result;
820
+ };
760
821
 
761
822
  return blockingSend(action);
762
823
  }
@@ -2,7 +2,8 @@
2
2
  // @ts-check
3
3
  // @jessie-check
4
4
 
5
- import '@endo/init/unsafe-fast.js';
5
+ // This file functions as both an importable module and a standalone script.
6
+ import './helpers/maybe-unsafe-lockdown.js';
6
7
 
7
8
  import os from 'os';
8
9
  import process from 'process';
@@ -0,0 +1,8 @@
1
+ import 'ses';
2
+ import '@endo/eventual-send/shim.js';
3
+
4
+ try {
5
+ lockdown({ __hardenTaming__: 'unsafe' });
6
+ } catch (_err) {
7
+ // ignore
8
+ }
@@ -2,7 +2,8 @@
2
2
  // @ts-check
3
3
  // @jessie-check
4
4
 
5
- import '@endo/init/unsafe-fast.js';
5
+ // This file functions as both an importable module and a standalone script.
6
+ import './helpers/maybe-unsafe-lockdown.js';
6
7
 
7
8
  import os from 'os';
8
9
  import process from 'process';
package/tools/test-kit.js CHANGED
@@ -1,27 +1,30 @@
1
1
  /* eslint-env node */
2
2
 
3
+ import fs from 'node:fs';
3
4
  import * as fsPromises from 'node:fs/promises';
4
- import * as pathNamespace from 'node:path';
5
+ import nativePath from 'node:path';
6
+
7
+ import tmp from 'tmp';
5
8
  import { Fail } from '@endo/errors';
9
+
6
10
  import {
7
11
  SwingsetMessageType,
8
12
  QueuedActionType,
9
13
  } from '@agoric/internal/src/action-types.js';
10
- import { makeInitMsg } from '@agoric/internal/src/chain-utils.js';
14
+ import * as STORAGE_PATH from '@agoric/internal/src/chain-storage-paths.js';
11
15
  import { deepCopyJsonable } from '@agoric/internal/src/js-utils.js';
12
16
  import { initSwingStore } from '@agoric/swing-store';
13
- import { makeSlogSender } from '@agoric/telemetry';
14
- import { launch } from '../src/launch-chain.js';
15
- import { DEFAULT_SIM_SWINGSET_PARAMS } from '../src/sim-params.js';
17
+
16
18
  import {
17
- makeBufferedStorage,
18
- makeKVStoreFromMap,
19
- } from '../src/helpers/bufferedStorage.js';
20
- import { makeQueue, makeQueueStorageMock } from '../src/helpers/make-queue.js';
19
+ extractPortNums,
20
+ makeLaunchChain,
21
+ makeQueueStorage,
22
+ } from '../src/chain-main.js';
23
+ import { DEFAULT_SIM_SWINGSET_PARAMS } from '../src/sim-params.js';
24
+ import { makeQueue } from '../src/helpers/make-queue.js';
21
25
 
22
26
  /** @import { BlockInfo, InitMsg } from '@agoric/internal/src/chain-utils.js' */
23
- /** @import { Mailbox, ManagerType, SwingSetConfig } from '@agoric/swingset-vat' */
24
- /** @import { KVStore } from '../src/helpers/bufferedStorage.js' */
27
+ /** @import { ManagerType, SwingSetConfig } from '@agoric/swingset-vat' */
25
28
  /** @import { InboundQueue } from '../src/launch-chain.js'; */
26
29
 
27
30
  /**
@@ -36,30 +39,28 @@ const stripUndefined = obj =>
36
39
  );
37
40
 
38
41
  /** @type {InitMsg} */
39
- export const defaultInitMessage = harden(
40
- makeInitMsg({
41
- type: SwingsetMessageType.AG_COSMOS_INIT,
42
- blockHeight: 100,
43
- blockTime: Math.floor(Date.parse('2020-01-01T00:00Z') / 1000),
44
- chainID: 'localtest',
45
- params: DEFAULT_SIM_SWINGSET_PARAMS,
46
- supplyCoins: [],
42
+ export const defaultInitMessage = harden({
43
+ type: SwingsetMessageType.AG_COSMOS_INIT,
44
+ blockHeight: 100,
45
+ blockTime: Math.floor(Date.parse('2020-01-01T00:00Z') / 1000),
46
+ chainID: 'localtest',
47
+ params: DEFAULT_SIM_SWINGSET_PARAMS,
48
+ supplyCoins: [],
47
49
 
48
- // cosmos-sdk module port mappings are generally ignored in testing, but
49
- // relevant in live blockchains.
50
- // Include them with unpredictable values.
51
- ...Object.fromEntries(
52
- Object.entries({
53
- storagePort: 0,
54
- swingsetPort: 0,
55
- vbankPort: 0,
56
- vibcPort: 0,
57
- })
58
- .sort(() => Math.random() - 0.5)
59
- .map(([name, _zero], i) => [name, i + 1]),
60
- ),
61
- }),
62
- );
50
+ // cosmos-sdk module port mappings are generally ignored in testing, but
51
+ // relevant in live blockchains.
52
+ // Include them with unpredictable values.
53
+ ...Object.fromEntries(
54
+ Object.entries({
55
+ storagePort: 0,
56
+ swingsetPort: 0,
57
+ vbankPort: 0,
58
+ vibcPort: 0,
59
+ })
60
+ .sort(() => Math.random() - 0.5)
61
+ .map(([name, _zero], i) => [name, i + 1]),
62
+ ),
63
+ });
63
64
  /** @type {InitMsg} */
64
65
  export const defaultBootstrapMessage = harden({
65
66
  ...deepCopyJsonable(defaultInitMessage),
@@ -170,7 +171,7 @@ export const makeCosmicSwingsetTestKit = async (
170
171
  fixupInitMessage,
171
172
  fixupConfig,
172
173
  slogSender,
173
- swingsetConfig = {},
174
+ swingsetConfig,
174
175
  swingStore,
175
176
  vats,
176
177
 
@@ -179,7 +180,7 @@ export const makeCosmicSwingsetTestKit = async (
179
180
  addBootstrapBehaviors,
180
181
  bootstrapCoreEvals,
181
182
  } = {},
182
- { fsp = fsPromises, resolvePath = pathNamespace.resolve } = {},
183
+ { fsp = fsPromises, resolvePath = nativePath.resolve } = {},
183
184
  ) => {
184
185
  await null;
185
186
  /** @type {SwingSetConfig} */
@@ -216,42 +217,46 @@ export const makeCosmicSwingsetTestKit = async (
216
217
  if (initMessage.isBootstrap === undefined && !swingStore) {
217
218
  initMessage.isBootstrap = true;
218
219
  }
220
+ const portNums = extractPortNums(initMessage);
221
+ const knownPorts = new Map(
222
+ Object.entries(portNums).map(([name, value]) => [value, name]),
223
+ );
219
224
 
220
225
  if (!swingStore) swingStore = initSwingStore(); // in-memory
221
226
  const { hostStorage } = swingStore;
222
227
 
223
- const actionQueueStorage = makeQueueStorageMock().storage;
224
- const highPriorityQueueStorage = makeQueueStorageMock().storage;
225
- const { kvStore: mailboxKVStore, ...mailboxBufferMethods } =
226
- makeBufferedStorage(
227
- /** @type {KVStore<Mailbox>} */ (makeKVStoreFromMap(new Map())),
228
- );
229
- const mailboxStorage = { ...mailboxKVStore, ...mailboxBufferMethods };
230
-
231
- const savedChainSends = [];
232
- const clearChainSends = async () => savedChainSends.splice(0);
233
- const replayChainSends = (..._args) => {
234
- throw Error('not implemented');
228
+ const fakeAgcc = {
229
+ /** @type {(destPort: unknown, msgJson: string) => string} */
230
+ send: (destPort, msgJson) => {
231
+ const portName =
232
+ knownPorts.get(destPort) || Fail`unknown cosmos port ${destPort}`;
233
+ const msg = JSON.parse(msgJson);
234
+ const result = receiveBridgeSend(portName, msg);
235
+ return JSON.stringify(result);
236
+ },
235
237
  };
238
+ const actionQueueStorage = makeQueueStorage(
239
+ msg => fakeAgcc.send(portNums.storage, msg),
240
+ STORAGE_PATH.ACTION_QUEUE,
241
+ );
242
+ const highPriorityQueueStorage = makeQueueStorage(
243
+ msg => fakeAgcc.send(portNums.storage, msg),
244
+ STORAGE_PATH.HIGH_PRIORITY_QUEUE,
245
+ );
236
246
 
237
- if (!slogSender && (env.SLOGFILE || env.SLOGSENDER)) {
238
- slogSender = await makeSlogSender({ env });
239
- }
240
-
241
- const launchResult = await launch({
242
- swingStore,
243
- actionQueueStorage,
244
- highPriorityQueueStorage,
245
- mailboxStorage,
246
- clearChainSends,
247
- replayChainSends,
248
- bridgeOutbound: receiveBridgeSend,
249
- vatconfig: config,
250
- argv: { bootMsg: initMessage },
247
+ const { name: dbDir, removeCallback: cleanupDB } = tmp.dirSync({
248
+ prefix: debugName || 'testdb',
249
+ unsafeCleanup: true,
250
+ });
251
+ const launchChain = makeLaunchChain(fakeAgcc, dbDir, {
251
252
  env,
252
- debugName,
253
- slogSender,
254
- swingsetConfig,
253
+ fs,
254
+ path: nativePath,
255
+ testingOverrides: { debugName, slogSender, swingStore, vatconfig: config },
256
+ });
257
+ const launchResult = await launchChain({
258
+ ...initMessage,
259
+ resolvedConfig: swingsetConfig,
255
260
  });
256
261
  const { blockingSend, shutdown: shutdownKernel } = launchResult;
257
262
  /** @type {(options?: { kernelOnly?: boolean }) => Promise<void>} */
@@ -259,6 +264,7 @@ export const makeCosmicSwingsetTestKit = async (
259
264
  await shutdownKernel();
260
265
  if (kernelOnly) return;
261
266
  await hostStorage.close();
267
+ await cleanupDB();
262
268
  };
263
269
 
264
270
  // Remember information about the current block, starting with the init
@@ -379,7 +385,6 @@ export const makeCosmicSwingsetTestKit = async (
379
385
  // SwingSet-oriented references.
380
386
  actionQueue,
381
387
  highPriorityQueue,
382
- mailboxStorage,
383
388
  shutdown,
384
389
  swingStore,
385
390